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

本文关键字:XAML 文件 位置 Binding 失败 取决于 绑定 | 更新日期: 2023-09-27 18:26:40

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

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

即属性CCD_ 1被绑定到周围窗口的数据上下文。当窗口的DataContext的值发生变化时,绑定有时会更新,有时不会更新;这取决于CCD_ 3在XAML文件中的位置。

以下是一个示例(EDIT:我将{Binding}更改为{Binding Path=DataContext, ElementName=myWindow},以强调该问题与DataContext的继承无关):

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
    }
}

第一个按钮";设置数据上下文";以更改数据上下文。然后按下按钮";读取绑定属性";,显示此消息的:

bindfails.Data=空

bindworks.Data=1234

显然,数据绑定只针对StackPanel的子元素MyClass进行了更新;但对于CCD_ 10所引用的CCD_。

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

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:找不到引用为"ElementName=myWindow"的绑定的源。

显然,ElementName属性只搜索可视化树或逻辑树,尽管WPF在线文档中没有对此进行说明。可能没有简单的方法可以在XAML中设置这样的绑定。

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

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

请参阅:依赖属性标识符字段:FrameworlElement 中的DataContextProperty

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

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

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

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

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

另一种使其工作的简单方法是从Window.Tag中取出bindfails,并将其放置在Window中的某个位置,即StackPanel中。接下来,在Window的构造函数中,编写<local:MyClass...>0。如果不希望TextBox出现在表单中,可以将其Visibility设置为Collapsed(或将其放在折叠的容器控件中)。