绑定有时会失败,具体取决于XAML文件中{Binding}的位置

时间:2012-03-05 19:11:31

标签: c# wpf xaml data-binding

我的程序包含此行的几个实例:

<local:MyClass Data="{Binding}"/>

即。属性Data绑定到周围窗口的数据上下文。当窗口DataContext的值发生变化时,绑定有时会更新,有时不会更新;它取决于<local:MyClass...>在XAML文件中的位置。

以下是一个示例(编辑:我将{Binding}更改为{Binding Path=DataContext, ElementName=myWindow}以强调问题与DataContext的继承无关:< / p>

XAML代码:

<Window x:Class="BindTest.MainWindow"
        x:Name="myWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BindTest"
        Title="Binding Test" Height="101" Width="328">
    <Window.Tag>
        <local:MyClass x:Name="bindfails" Data="{Binding Path=DataContext, ElementName=myWindow}"/>
    </Window.Tag>

    <StackPanel Orientation="Horizontal">
        <Button Margin="5" Padding="5" Click="SetButtonClicked">Set DataContext</Button>
        <Button Margin="5" Padding="5" Click="ReadButtonClicked">Read Bound Property</Button>
        <local:MyClass x:Name="bindworks" Data="{Binding Path=DataContext, ElementName=myWindow}"/>
    </StackPanel>
</Window>

C#代码:

using System.Windows;

namespace BindTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void SetButtonClicked(object sender, RoutedEventArgs e)
        {
            DataContext = 1234;
        }

        private void ReadButtonClicked(object sender, RoutedEventArgs e)
        {
            string txtA = (bindfails.Data == null ? "null" : bindfails.Data.ToString());
            string txtB = (bindworks.Data == null ? "null" : bindworks.Data.ToString());
            MessageBox.Show(string.Format("bindfails.Data={0}\r\nbindworks.Data={1}", txtA, txtB));
        }
    }

    public class MyClass : FrameworkElement
    {
        #region Dependency Property "Data"

        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(MyClass), new UIPropertyMetadata(null));

        #endregion
    }
}

首先按下按钮&#34;设置DataContext&#34;更改数据上下文。然后按下按钮&#34; Read Bound Property&#34;,显示以下消息:

  

bindfails.Data =空

     

bindworks.Data = 1234

显然,数据绑定仅针对MyClass的子StackPanel元素进行了更新;但未更新MyClass引用的Window.Tag元素的数据绑定。

EDIT2:我还发现,在MainWindow的构造函数中以编程方式添加绑定时绑定有效:

Binding binding = new Binding("DataContext") {Source = this};
bindfails.SetBinding(MyClass.DataProperty, binding);

绑定仅在XAML中声明时失败。此外,问题并非针对DataContext;当我使用其他Window属性时也会发生这种情况,例如Title

任何人都可以解释这种行为并建议如何在这两种情况下允许在XAML中使用{Binding}吗?

EDIT3:以上代码并不完全等同于{Binding}标记扩展。 100%等效代码是:

Binding binding = new Binding("DataContext") {ElementName = "myWindow"};
bindfails.SetBinding(MyClass.DataProperty, binding);

当我使用该代码时,绑定也会失败(例如在XAML中绑定时),并且以下诊断消息将写入调试输出:

  

System.Windows.Data错误:4:无法找到带引用的绑定源&#39; ElementName = myWindow&#39;。

显然,ElementName属性只搜索可视树或逻辑树,即使WPF在线文档中没有记录这一点。可能没有简单的方法在XAML中设置这样的绑定。

2 个答案:

答案 0 :(得分:1)

我认为它不起作用,因为当您编写{Binding}时,要绑定的数据的上下文将从父级继承。对于bindworks,它是StackPanel,从DataContext继承Window,但bindfails.Parent属性为null

我想知道你为什么要把一个控件放在Window的标签元素中。如果由于某种原因必须将其保留在Tag节点中,则可以直接更新其DataContext,因此只需将SetButtonClicked方法更改为:

private void SetButtonClicked(object sender, RoutedEventArgs e)
{
    DataContext = 1234;
    bindfails.DataContext = DataContext;
}

使其发挥作用的另一种简单方法是从bindfails中取出Window.Tag并将其放在Window中的某个位置,即StackPanel。 接下来,在Window的构造函数中,编写this.Tag = bindfails。如果您不希望TextBox显示在表单中,可以将其Visibility设置为Collapsed(或将其放在折叠的容器控件中)。

答案 1 :(得分:1)

dataContext仅通过对象树传递。 Property标记不在可视树中,并且不会响应DataContext更改的Event,并且在没有此事件的情况下不会刷新绑定。

见: 依赖属性标识符字段:来自FrameworlElement的DataContextProperty

数据上下文是一个允许对象从对象树中的父对象继承绑定指定信息的概念

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.datacontext(v=vs.95).aspx