views:

1669

answers:

2

I can bind to a property, but not a property within another property. Why not? e.g.

<Window DataContext="{Binding RelativeSource={RelativeSource Self}}"...>
...
    <!--Doesn't work-->
    <TextBox Text="{Binding Path=ParentProperty.ChildProperty,Mode=TwoWay}" 
             Width="30"/>

(Note: I'm not trying to do master-details or anything. Both properties are standard CLR properties.)

Update: the problem was that my ParentProperty depended on an object in XAML being initialized. Unfortunately that object was defined later in the XAML file than the Binding, so the object was null at the time when my ParentProperty was read by the Binding. Since rearranging the XAML file would screw up the layout, the only solution I could think of was to define the Binding in code-behind:

<TextBox x:Name="txt" Width="30"/>

// after calling InitializeComponent()
txt.SetBinding(TextBox.TextProperty, "ParentProperty.ChildProperty");
+1  A: 

All I can think of is that the ParentProperty is being changed after the Binding is created, and it does not support change notification. Every property in the chain must support change notification, whether it be by virtue of being a DependencyProperty, or by implementing INotifyPropertyChanged.

HTH, Kent

Kent Boogaart
Yes, that seems to sort-of be the reason. The ParentProperty is read-only but it depends on a certain control in XAML being initialized. This object is defined in the .xaml file AFTER the Binding, so when ParentProperty was called, it threw NullReferenceException. I didn't notice because WPF swallowed it. I should have checked the output window!
Qwertie
Now I have a new puzzle - how to define the objects in the correct order in XAML without messing up the layout.
Qwertie
Or can I somehow make the Binding wait until the Window is fully initialized before it reads the property? When I use {Binding ElementName=xyz, ...}, it works even if xyz is defined later in the XAML file. Strange then that my ParentProperty (which uses element xyz) doesn't work just because xyz is defined later in the XAML file.
Qwertie
Easiest way would be to set the DataContext after you've initialized in the code behind rather than in XAML. That makes sense because otherwise your program is doing work unnecessarily with a data object that isn't ready yet.
Kent Boogaart
A: 

Do both the ParentProperty and your class implement INotifyPropertyChanged?

    public class ParentProperty : INotifyPropertyChanged
    {
        private string m_ChildProperty;

        public string ChildProperty
        {
            get
            {
                return this.m_ChildProperty;
            }

            set
            {
                if (value != this.m_ChildProperty)
                {
                    this.m_ChildProperty = value;
                    NotifyPropertyChanged("ChildProperty");
                }
            }
        }

        #region INotifyPropertyChanged Members

        #endregion
    }

    public partial class TestClass : INotifyPropertyChanged
    {
        private ParentProperty m_ParentProperty;

        public ParentProperty ParentProperty
        {
            get
            {
                return this.m_ParentProperty;
            }

            set
            {
                if (value != this.m_ParentProperty)
                {
                    this.m_ParentProperty = value;
                    NotifyPropertyChanged("ParentProperty");
                }
            }
        }
}
    public TestClass()

    {
        InitializeComponent();
        DataContext = this;
        ParentProperty = new ParentProperty();
        ParentProperty.ChildProperty = new ChildProperty();

        #region INotifyPropertyChanged Members
        #endregion
    }