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

Posted

技术标签:

【中文标题】WPF:如何绑定到嵌套属性?【英文标题】:WPF: How to bind to a nested property? 【发布时间】:2010-11-01 23:37:00 【问题描述】:

我可以绑定到一个属性,但不能绑定到另一个属性中的一个属性。为什么不?例如

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

(注意:我不想做主细节或任何事情。这两个属性都是标准 CLR 属性。)

更新:问题是我的 ParentProperty 依赖于正在初始化的 XAML 中的对象。不幸的是,该对象在 XAML 文件中的定义比绑定晚,因此在绑定读取我的 ParentProperty 时该对象为空。由于重新排列 XAML 文件会破坏布局,我能想到的唯一解决方案是在代码隐藏中定义绑定:

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

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

【问题讨论】:

【参考方案1】:

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

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

请注意,在您的 DataContextTextBox 未准备好绑定之前,Text 属性将不会“建立” - 您可以将 FallbackValue='error' 添加为绑定参数 - 这将类似于指示器,它将显示绑定是否正常。

【讨论】:

如何为 DataGridTextColumn 做到这一点?【参考方案2】:

我能想到的只是ParentPropertyBinding创建后被更改,它不支持更改通知。链中的每个属性都必须支持更改通知,无论是通过DependencyProperty,还是通过实现INotifyPropertyChanged

【讨论】:

是的,这似乎是原因。 ParentProperty 是只读的,但它取决于正在初始化的 XAML 中的某个控件。此对象在 Binding 之后的 .xaml 文件中定义,因此当调用 ParentProperty 时,它会抛出 NullReferenceException。我没有注意到,因为 WPF 吞下了它。我应该检查一下输出窗口! 现在我有了一个新的谜题——如何在 XAML 中以正确的顺序定义对象而不弄乱布局。 或者我可以让绑定等到窗口完全初始化后再读取属性吗?当我使用 Binding ElementName=xyz, ... 时,即使 xyz 稍后在 XAML 文件中定义,它也可以工作。奇怪的是,我的 ParentProperty(它使用元素 xyz)不能工作,只是因为 xyz 稍后在 XAML 文件中定义。 最简单的方法是在后面的代码而不是 XAML 中初始化之后设置 DataContext。这是有道理的,因为否则您的程序正在使用尚未准备好的数据对象进行不必要的工作。【参考方案3】:

ParentProperty 和您的类是否都实现了 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,即使它不是正在更改的子属性?在我的例子中,父对象被设置,这就是改变......父对象有一个名为“名称”的属性,它实际上永远不会改变。但是绑定到 this 不起作用。令人惊讶的是,它确实适用于 XAML 设计器(它在设计时显示正确派生的子属性名称) - 所以我完全被难住了

以上是关于WPF:如何绑定到嵌套属性?的主要内容,如果未能解决你的问题,请参考以下文章

父属性更改时嵌套属性的 WPF 绑定更新通知

如何将索引属性绑定到 WPF 中的控件

如何将 WPF ListBoxItem 的 IsEnabled 属性绑定到其源项的属性?

WPF .Net 4 - OneWayToSource 绑定到只写属性适用于某些机器!如何?

WPF .Net 4 - OneWayToSource 绑定到只写属性适用于某些机器!如何?

如何将 Xml 属性绑定到 Treeview 节点,同时将 XDocument 数据绑定到 WPF Treeview