WPF:如何绑定到嵌套属性?

38
我可以绑定到一个属性,但不能绑定到另一个属性内部的属性。为什么呢?例如:
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}"...>
...
    <!--Doesn't work-->
    <TextBox Text="{Binding Path=ParentProperty.ChildProperty,Mode=TwoWay}" 
             Width="30"/>
<注意:我不是要做主从或任何其他事情。这两个属性都是标准的CLR属性。

更新:问题在于我的ParentProperty依赖于XAML中的一个对象被初始化。不幸的是,该对象在XAML文件中被定义在Binding之后,因此该对象在Binding读取ParentProperty时为空。由于重新排列XAML文件会破坏布局,我唯一想到的解决办法是在代码后台中定义绑定:

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

// after calling InitializeComponent()
txt.SetBinding(TextBox.TextProperty, "ParentProperty.ChildProperty");
3个回答

49

您也可以在XAML中为TextBox设置DataContext(我不知道这是否是最佳解决方案,但至少您不必手动在codeBehind中执行任何操作,只需实现INotifyPropertyChanged)。当您的TextBox已经有了继承的DataContext时,您可以像这样编写代码:

<TextBox 
   DataContext="{Binding Path=ParentProperty}"
   Text="{Binding Path=ChildProperty, Mode=TwoWay}" 
   Width="30"/>

请注意,在你的TextBoxDataContext准备好之前,Text属性的绑定将不会被“建立” - 你可以添加FallbackValue='error'作为绑定参数 - 这将是一个指示器,它将告诉你绑定是否正常。


1
我该如何在DataGridTextColumn中实现这个? - x19

27

我唯一能想到的就是,ParentPropertyBinding创建后被更改了,并且它不支持更改通知。 链中的每个属性都必须支持更改通知,无论它是通过成为DependencyProperty还是实现INotifyPropertyChanged来实现。


是的,这似乎是原因所在。ParentProperty是只读的,但它取决于XAML中某个控件的初始化。该对象在Binding之后在.xaml文件中定义,因此当调用ParentProperty时,它会抛出NullReferenceException异常。我没有注意到,因为WPF已经将其吞掉了。我应该检查输出窗口! - Qwertie
现在我有一个新的难题 - 如何在 XAML 中正确定义对象顺序而不会弄乱布局。 - Qwertie
或者我可以以某种方式使绑定在窗口完全初始化之前等待读取属性吗?当我使用{Binding ElementName=xyz, ...}时,即使xyz在XAML文件中稍后定义,它也能正常工作。奇怪的是,我的ParentProperty(使用元素xyz)却不起作用,只因为xyz在XAML文件中稍后定义。 - Qwertie
1
最简单的方法是在代码后台初始化之后设置DataContext,而不是在XAML中设置。这是有道理的,因为否则你的程序会在数据对象还没有准备好的情况下不必要地进行工作。 - Kent Boogaart

4

父属性和你的类是否都实现了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
    }

即使不是更改子属性,两者都需要实现INotifyPropertyChanged吗?在我的情况下,父对象被设置为更改...父对象有一个名为“Name”的属性,它从未更改。但是绑定到此属性无效。令人惊讶的是,在XAML设计器中它可以工作(在设计时显示正确派生的子属性名称)-所以我完全被难住了。 - PandaWood

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接