none
Usercontrol Dependency Property not binding

    Question

  • Hi,

    I have a usercontrol that binds a property to a text box which is registered as such:

     

    public static readonly DependencyProperty TitleProperty =
                 DependencyProperty.Register("Title", typeof(String),
                 typeof(PromptBox), new FrameworkPropertyMetadata("My Title",FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(TitlePropertyChangedCallBack)));
    
            static void TitlePropertyChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
            {
             //  tbd
            }
            
            public string Title
            {
                get
                {
                    return (String)GetValue(TitleProperty); 
                }
                set
                {
                    SetValue(TitleProperty, value);
                }
            }
    

     


    I am now trying to Bind this property to a window property that inherits INotifyPropertyChanged

     

    <local:NavigationPage
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Luna"
    	xmlns:local="clr-namespace:tad" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable="d"
    	x:Class="tad.SelectBy"
    	x:Name="Page"
    	WindowTitle="Page"
    	FlowDirection="LeftToRight"
    	WindowWidth="640" WindowHeight="480"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    
    	
    
    	<Grid x:Name="LayoutRoot">
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="0.241*"/>
    			<ColumnDefinition Width="0.759*"/>
    		</Grid.ColumnDefinitions>
    		<Grid.RowDefinitions>
    			<RowDefinition Height="0.731*"/>
    			<RowDefinition Height="0.269*"/>
    		</Grid.RowDefinitions>
    		<Button x:Name="buyMMY" Content="MMY" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,10,0,0" Height="60" Width="90" FontSize="18.667" MouseEnter="buyMMY_MouseEnter" Click="buyMMY_Click"/>
            <Button x:Name="buyPart" Content="Part No." HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,98,0,0" Height="60" Width="90" FontSize="18.667" MouseEnter="buyPart_MouseEnter" Click="butyPart_Click"/>
            <local:PromptBox x:Name="pbPrompt" Margin="0,12,23.966,0" Title="{Binding PromptTitle, Mode=TwoWay}" Body="Use the buttons opposite in order to choose your preferred method of sensor selection" VerticalAlignment="Top" d:LayoutOverrides="Width" Grid.Column="1" HorizontalAlignment="Left"/>
        </Grid>
    </local:NavigationPage>
    

    However, when the variable changes it does not seem to update the dependency property.

     

    If I create a simple Textblock on the window and bind the Text to the same variable this works.

    Can anyone please spot where I am going wrong?

    Thanks.


    • Edited by LucaUWF Friday, September 30, 2011 3:34 PM
    Friday, September 30, 2011 3:12 PM

Answers

  • Below is a sample which is working.

    Window XAML:

    <Window x:Class="SampleSep30_DependencyProperty.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525"
            xmlns:local="clr-namespace:SampleSep30_DependencyProperty"
            DataContext="{Binding RelativeSource={RelativeSource Self}}">
        <StackPanel>
            <Button Click="Button_Click">Click Me!</Button>
            <local:DPUserControl Title="{Binding Path=TextSource}" />
        </StackPanel>
    </Window>
    

    Window code behind:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.ComponentModel;
    
    namespace SampleSep30_DependencyProperty
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window, INotifyPropertyChanged
        {
            public MainWindow()
            {
                InitializeComponent();
            }
            private string _textSource = "Sample";
            public string TextSource
            {
                get { return _textSource; }
                set { _textSource = value; OnPropertyChanged("TextSource"); }
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                TextSource = "Hello!";            
            }
    
            public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            public event PropertyChangedEventHandler PropertyChanged;
        }
    }
    

    User Control XAML:

    <UserControl x:Class="SampleSep30_DependencyProperty.DPUserControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}" />
        </Grid>
    </UserControl>
    

    User Control code behind:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace SampleSep30_DependencyProperty
    {
        /// <summary>
        /// Interaction logic for DPUserControl.xaml
        /// </summary>
        public partial class DPUserControl : UserControl
        {
            public DPUserControl()
            {
                InitializeComponent();
            }
            public static readonly DependencyProperty TitleProperty =
                 DependencyProperty.Register("Title", typeof(String),
                 typeof(DPUserControl), new FrameworkPropertyMetadata("My Title", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(TitlePropertyChangedCallBack)));
    
            static void TitlePropertyChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
            {
                //  tbd
            }
    
            public string Title
            {
                get
                {
                    return (String)GetValue(TitleProperty);
                }
                set
                {
                    SetValue(TitleProperty, value);
                }
            }
    
        }
    }
    





    • Edited by Srini Kolan Saturday, October 1, 2011 2:29 AM
    • Marked as answer by LucaUWF Saturday, October 1, 2011 11:23 AM
    Saturday, October 1, 2011 12:27 AM
  • Thank you Srini.

    Your code helped identify the problem with this line:

    Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}"
    

     

    Adding the RelativeSource did the trick... I best go read up on what that actually does. :)


    • Edited by LucaUWF Saturday, October 1, 2011 11:23 AM
    • Marked as answer by LucaUWF Saturday, October 1, 2011 11:24 AM
    Saturday, October 1, 2011 7:13 AM

All replies

  • Looks like the DataContext of the PromptBox is going to be the NavigationPage, not the window.  If your property is defined in your Window, then you will need to set the DataContext of the PromptBox to the window.

    Cause by in your NavigationPage:

     

     DataContext="{Binding RelativeSource={RelativeSource Self}}" 
    • Edited by KP_SES Friday, September 30, 2011 5:18 PM
    Friday, September 30, 2011 5:16 PM
  • Sorry, the property is actually in the navigationpage which inherits page, not the window itself.

    This page is hosted in a frame on a window.

    • Edited by LucaUWF Friday, September 30, 2011 6:16 PM
    Friday, September 30, 2011 6:03 PM
  • OK.

    I was slightly concerned that the problem may have been associated with the inheritance, so I moved it all to a Window.

    I bound a Textblock (that works) and the PromptBox.Title to the same INPC and observed that when the OnPropertyChanged event is called for the PromptBox that this.PropertyChanged is null, whereas it is not for the TextBlock.

    Even with both controls on the window together the TextBlock is updated but the PromptBox.Title is not.

    Clearly it's associated with passing of NULL.

     

    Not sure why though...


    Friday, September 30, 2011 6:50 PM
  •  When the CLR property changes, does the TitlePropertyChangedCallback method get hit? 

     

    I didn't follow you on this:

    "I bound a Textblock (that works) and the PromptBox.Title to the same INPC and observed that when the OnPropertyChanged event is called for the PromptBox that this.PropertyChanged is null, whereas it is not for the TextBlock."

    Friday, September 30, 2011 7:23 PM
  •  

    No, the TitlePropertyChangedCallback is not called.

     

    My point on the part that you quoted above is that when the PromptTitle property is modified e.g.

    PromptTitle = "Foo";

    and the OnPropertyChanged is raised, the PrompertyChanged value is null:


    public string PromptTitle
            {
                get
                {
                    return promptTitle;
                }
                set
                {
                    promptTitle = value;
                    OnPropertyChanged("PromptTitle");
                }
            }

     

    void OnPropertyChanged(string propName)
            {
                if (this.PropertyChanged != null) //doesn't go beyond this point as
    PropertyChanged is null
                    this.PropertyChanged(
                        this, new PropertyChangedEventArgs(propName));
            }


    I'm guessing the problem is related to binding to the UserControl, since if I bind in exactly the same manner to a TextBlock.Text property the binding works correctly.

    I'm at a loss with this. :(
    • Proposed as answer by Srini Kolan Saturday, October 1, 2011 12:25 AM
    • Unproposed as answer by Srini Kolan Saturday, October 1, 2011 12:26 AM
    Friday, September 30, 2011 9:55 PM
  • Below is a sample which is working.

    Window XAML:

    <Window x:Class="SampleSep30_DependencyProperty.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525"
            xmlns:local="clr-namespace:SampleSep30_DependencyProperty"
            DataContext="{Binding RelativeSource={RelativeSource Self}}">
        <StackPanel>
            <Button Click="Button_Click">Click Me!</Button>
            <local:DPUserControl Title="{Binding Path=TextSource}" />
        </StackPanel>
    </Window>
    

    Window code behind:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.ComponentModel;
    
    namespace SampleSep30_DependencyProperty
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window, INotifyPropertyChanged
        {
            public MainWindow()
            {
                InitializeComponent();
            }
            private string _textSource = "Sample";
            public string TextSource
            {
                get { return _textSource; }
                set { _textSource = value; OnPropertyChanged("TextSource"); }
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                TextSource = "Hello!";            
            }
    
            public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            public event PropertyChangedEventHandler PropertyChanged;
        }
    }
    

    User Control XAML:

    <UserControl x:Class="SampleSep30_DependencyProperty.DPUserControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}" />
        </Grid>
    </UserControl>
    

    User Control code behind:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace SampleSep30_DependencyProperty
    {
        /// <summary>
        /// Interaction logic for DPUserControl.xaml
        /// </summary>
        public partial class DPUserControl : UserControl
        {
            public DPUserControl()
            {
                InitializeComponent();
            }
            public static readonly DependencyProperty TitleProperty =
                 DependencyProperty.Register("Title", typeof(String),
                 typeof(DPUserControl), new FrameworkPropertyMetadata("My Title", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(TitlePropertyChangedCallBack)));
    
            static void TitlePropertyChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
            {
                //  tbd
            }
    
            public string Title
            {
                get
                {
                    return (String)GetValue(TitleProperty);
                }
                set
                {
                    SetValue(TitleProperty, value);
                }
            }
    
        }
    }
    





    • Edited by Srini Kolan Saturday, October 1, 2011 2:29 AM
    • Marked as answer by LucaUWF Saturday, October 1, 2011 11:23 AM
    Saturday, October 1, 2011 12:27 AM
  • Hi,

    if ur binding is not working on the textbox then try to use UpdateSourceTrigger = "PropertyChanged" on the binding like

    Text = {"Binding TitleProperty, UpdateSoutceTrigger = PropertyChanged"}

     


    Thanks, BHavik
    Saturday, October 1, 2011 5:24 AM
  • Thank you Srini.

    Your code helped identify the problem with this line:

    Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}"
    

     

    Adding the RelativeSource did the trick... I best go read up on what that actually does. :)


    • Edited by LucaUWF Saturday, October 1, 2011 11:23 AM
    • Marked as answer by LucaUWF Saturday, October 1, 2011 11:24 AM
    Saturday, October 1, 2011 7:13 AM