none
Binding To a User Defined Dependancy Property

    Question

  • I'm still new to WPF so I'm sorry if this doesn't make sense.

    I have created a control that inherits from UserControl called MyUserControl.  I want to use this in another project and have that working.  I then created a dependency property called TestText that is a string.  This will get displayed in the text box via data binding in MyUserControl.  If I explicitly set this it works just fine.  I want to be able to bind to that property from the window that is hosting the control.  However when I try to bind in XAML it doesn't seem to update the field.  When I bind using code it works.  I'm fairly sure my XAML is okay because I can bind the to a label's content alright.  Here is the code I am using:

    MyUserControl.xaml.cs:

    namespace CustomControlLibrary1
    {
      /// <summary>
      /// Interaction logic for UserControl1.xaml
      /// </summary>

      public partial class MyUserControl : System.Windows.Controls.UserControl
      {

        private void OnPropertyChanged(String PropertyName)
        {
          if (PropertyChanged != null)
          {
            PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
          }
        }

        // DependencyProperty and property.
        public static readonly DependencyProperty TextTestProperty;

        public string TextTest
        {
          set
          {
            SetValue(TextTestProperty, value);
          }
          get
          {
            return (string)GetValue(TextTestProperty);
          }
        }

        public MyUserControl()
        {
          InitializeComponent();
        }

            // Static constructor.
        static MyUserControl()
        {
          // Define the metadata.
          FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
          metadata.DefaultValue = null;
          metadata.AffectsMeasure = true;
          metadata.Inherits = false;
          metadata.BindsTwoWayByDefault = true;
          metadata.IsNotDataBindable = false;

          // Register the DependencyProperty.
          TextTestProperty =               
               DependencyProperty.Register("TextTest", typeof(string),
                                            typeof(MyUserControl), metadata);
        }

        void btnValue_Click(object sender, RoutedEventArgs e)
        {
          TextTest = TextTest;
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

      }
    }

    MyUserControl.xaml

    <UserControl x:Class="CustomControlLibrary1.MyUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}" >
      <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" DockPanel.Dock="Top">

        <Label x:Name="lblValue" Content="LabelData" />
        <TextBox x:Name="txtValue" Grid.Row="1" Grid.Column="1" Text="{Binding TextTest}" />
        <Button Name="btnValue" Grid.Row="1" Grid.Column="1"
              Click="btnValue_Click"  HorizontalAlignment="Right" Padding="0,0,0,0" Margin="0,2,0,2">
          ...
        </Button>
      
      </StackPanel>
    </UserControl>

    MyWindow:xaml.cs

      public partial class MyWindow : System.Windows.Window, INotifyPropertyChanged
      {
        private void OnPropertyChanged(String PropertyName)
        {
          if (PropertyChanged != null)
          {
            PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
          }
        }


        private string _inputText;
        public string InputText
        {
          get { return _inputText; }
          set
          {
            _inputText = value;
            OnPropertyChanged("InputText");
          }
        }

        public MyWindow()
        {
          InitializeComponent();
          InputText = "DISPLAY TEXT";

          // Binding MyBinding = new Binding("InputText");
          // MyBinding.Source = CurrentWindow;
          // UControl.SetBinding(MyUserControl.TextTestProperty , MyBinding);

        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

      }
    }

    MyWindow.xaml
    <Window x:Class="TestApp.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestApp" Height="300" Width="300"
        xmlns:CustomConrtolLibrary1="clr-namespace:CustomControlLibrary1;assembly=CustomControlLibrary1"
        Name="CurrentWindow"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        >
        <StackPanel>
          <Label Content="{Binding InputText}" />
          <CustomConrtolLibrary1:MyUserControl Name="UControl"  TextTest="{Binding InputText}" />
        </StackPanel>
      </Window>


    If I uncomment the binding code in MyWindow's constructor it works fine.
    Any ideas?





    Monday, October 23, 2006 5:00 PM

Answers

  • You should do

    <CustomConrtolLibrary1:MyUserControl Name="UControl" TextTest="{Binding ElementName=CurrentWindow, Path=InputText}" />

    without the ElementName

    you get the Warning

    System.Windows.Data Error: 35 : BindingExpression path error: 'InputText' property not found on 'object' ''MyUserControl' (Name='UControl')'. BindingExpression:Path=InputText; DataItem='MyUserControl' (Name='UControl'); target element is 'MyUserControl' (Name='UControl'); target property is 'TextTest' (type 'String')

    Monday, October 23, 2006 6:29 PM
    Moderator

All replies

  • you could do

      Binding MyBinding = new Binding("InputText");
      MyBinding.Source = this;
      UControl.SetBinding(MyUserControl.TextTestProperty , MyBinding);

    or

    Binding MyBinding = new Binding("InputText");
      MyBinding.ElementName= CurrentWindow;
      UControl.SetBinding(MyUserControl.TextTestProperty , MyBinding);

    Monday, October 23, 2006 5:09 PM
    Moderator
  • Lee - First, thanks for responding.  I really do appreciate it.

    I have tried that.  Infact you will see in MyWindow's constructor your second example
    commented it out 

    That works, but when I do the equivalent in XAML it doesn't:

    I setup the DataContext using :

    <Window x:Class="TestApp.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestApp" Height="300" Width="300"
     xmlns:CustomConrtolLibrary1="clr-namespace:CustomControlLibrary1;assembly=CustomControlLibrary1"
        Name="CurrentWindow"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"

    Then to bind to a label's content I do this and it works:

    <Label Content="{Binding InputText}" />

    But when I try the same syntax to bind to my custom property "TextTest" it doesn't work.

    <CustomConrtolLibrary1:MyUserControl Name="UControl"  TextTest="{Binding InputText}" />


    It's odd because if I setup the binding in code it works fine.  When I do it in XAML it doesn't.  It is also odd because when I bind to a Label's property in XAML it works.  But when I try the same thing for MyControl it doesn't.

    This concerns me in two ways:  We are trying to take the idea of separating the UI from the business logic so it would be nice to define binding in XAML when possible.  And second it's just weird to me.  I'm wondering if I didn't set up my dependency property correctly or something.

    Thanks again for the input.
    Monday, October 23, 2006 6:13 PM
  • You should do

    <CustomConrtolLibrary1:MyUserControl Name="UControl" TextTest="{Binding ElementName=CurrentWindow, Path=InputText}" />

    without the ElementName

    you get the Warning

    System.Windows.Data Error: 35 : BindingExpression path error: 'InputText' property not found on 'object' ''MyUserControl' (Name='UControl')'. BindingExpression:Path=InputText; DataItem='MyUserControl' (Name='UControl'); target element is 'MyUserControl' (Name='UControl'); target property is 'TextTest' (type 'String')

    Monday, October 23, 2006 6:29 PM
    Moderator
  • Fantastic!  That worked.  I actually don't get that warning that you see.  It would be useful it it showed up.

    I think I finally get what was going wrong here.  I set the DataContext="{Binding RelativeSource={RelativeSource Self}}"  in both MyWindow and MyUserControl.  So when we got to the first label in MyWindow the DataContext=CurrentWindow.  But when we got to MyUserControl the DataContext=UControl instead and InputText didn't exist.  This is not the behavior I was expecting, I would have guessed that the DataContext wouldn't' have changed.

    It's just so hard to debug XAML it makes little things like this diffucult to see what is going on.

    Thanks again for the help Lee!


    Monday, October 23, 2006 7:06 PM