为啥在 XAML 中绑定 MainWindow 数据上下文与使用 this.datacontext=this 在代码隐藏中绑定的行为不同?

Posted

技术标签:

【中文标题】为啥在 XAML 中绑定 MainWindow 数据上下文与使用 this.datacontext=this 在代码隐藏中绑定的行为不同?【英文标题】:Why does binding the MainWindow datacontext in XAML fail to act the same as binding in the codebehind with this.datacontext=this?为什么在 XAML 中绑定 MainWindow 数据上下文与使用 this.datacontext=this 在代码隐藏中绑定的行为不同? 【发布时间】:2013-02-18 18:15:36 【问题描述】:

我正在尝试使用数据绑定将 ObservableCollection 绑定到 DataGrid 的 ItemsSource,因为我了解 WPF 和其他东西。

在代码隐藏中,我可以使用this.DataContext = this;bloopDataGrid.DataContext = this; 设置DataContext。这很好,花花公子。

我想我可以尝试类似的东西

<Window.DataContext>
    <local:MainWindow/>
</Window.DataContext>

在我的主窗口中,但这会导致堆栈溢出异常,如this question 中所述。好吧,这有点道理。

在阅读了this 和其他问题/答案后,说要在窗口的 XAML 代码中尝试DataContext="Binding RelativeSource=RelativeSource Self",我想我可以实际上做到这一点。显然我不能。或者至少,IDE 允许我并且它在语法上是正确的,但没有做我想要的(即,正是 this.DataContext = this; 所做的)。

然后我阅读了this 关于使用"Binding ElementName=, Path=" 并尝试像这样使用它:

<DataGrid
    Name="bloopDataGrid"
    Grid.Row="1"
    ItemsSource="Binding ElementName=testWin, Path=OutputCollection">
</DataGrid>

这也不起作用。也许不是出于同样的原因,但我无法弄清楚它的问题。

奇怪的是,我无法复制Rachel Lim's blog post 中显示的重新绑定示例。

XAML:

<Window
    x:Class="DataBinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Height="350"
    Width="525"
    x:Name="testWin">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Content="Binding text">   
        </Label>

        <DataGrid
            Name="bloopDataGrid"
            Grid.Row="1"
            ItemsSource="Binding Path=OutputCollection">
        </DataGrid>
    </Grid>
</Window>

C#:

using System;
using System.Collections.ObjectModel; //For ObservableCollection<T>
using System.Windows;

namespace DataBinding

    public partial class MainWindow : Window
    
        public String text  get; set; 
        public ObservableCollection<testStruct> OutputCollection  get; set; 

        public struct testStruct
        
            public testStruct(String x, String y) : this()
            
                Col1 = x;
                Col2 = y;
            
            public String Col1  get; set; 
            public String Col2  get; set; 
        

        public MainWindow()
        
            InitializeComponent();

            testA t1 = new testA();
            this.DataContext = this;
            //this.DataContext = t1;
            //bloopDataGrid.DataContext = this;
            text = "bound \"this\"";
            t1.text = "bound a class";

            OutputCollection = new ObservableCollection<testStruct>();
            OutputCollection.Add(new testStruct("1", "2"));
            OutputCollection.Add(new testStruct("3", "4"));
        

        public class testA
        
            public String text  get; set; 
        

    

上面的代码是我用来测试的,目前正在使用正确给我的代码隐藏版本

我做错了什么,导致我无法获得与上图相同的结果,而是使用 XAML 进行 DataContext 处理?我没有正确连接点吗? ...我错过了一些点吗?

【问题讨论】:

【参考方案1】:
<Window.DataContext>
    <local:MainWindow/>
</Window.DataContext>

不一样
this.DataContext = this;

第一个是创建MainWindow 类的新实例并将其分配给WindowDataContext 属性,而第二个是将Window 的相同实例分配给它的@987654328 @属性。

为了在 XAML 中实现这一点,您需要使用 RelativeSource 绑定:

<Window DataContext="Binding RelativeSource=RelativeSource Self">
</Window>

编辑:

在 XAML 和后面的代码中定义 DataContext 的行为差异是由于构造函数完成执行时实际解析 XAML,因为 Dispatcher 等待用户代码(在构造函数中)窗口)在执行其挂起的操作之前完成。

这会导致这些不同时刻的实际属性值不同,并且由于没有INotifyPropertyChanged,WPF 无法更新 UI 以反映新值。

couldWindow 本身中实现 ​​INotifyPropertyChanged,但我建议为此创建一个 ViewModel,因为我不喜欢将 INotifyPropertyChanged(这更像是一个 ViewModel 概念)与DependencyObject-派生类(UI 元素)。

【讨论】:

我提到这对我不起作用,我通过查看其他问题来弄清楚 MainWindow 的问题所在。 您的问题是您将MainWindow 类本身内的数据元素混搭在一起。您应该创建一个 ViewModel 并实现 INotifyPropertyChanged 我不确定我是否理解。我是否仅限于对 WPF 中的所有程序遵循 MVVM 模式?开设新课程将如何解决我遇到的问题?我宁愿修复它或弄清楚它为什么不起作用,而不是因为我不理解它而严格避免它。 问题是你没有实现INotifyPropertyChanged,因此当这些属性发生变化时,用户界面永远不会得到通知。您也可以在Window 本身中实现它,但我不喜欢这种方法,因为WindowDependencyObject,我不喜欢将两者混合,因为我认为INotifyProeprtyChanged 更像是一个ViewModel 概念。 您对 INotifyPropertyChanged 的​​看法是正确的。我直接在 MainWindow 上实现它以查看是否是这种情况,现在当使用 DataContext="Binding RelativeSource=RelativeSource Self" 并触发事件时它可以工作。如果您更改答案以反映这一点(以及这些 cmets 中提到的其他内容),我会接受,否则我会自己回答。

以上是关于为啥在 XAML 中绑定 MainWindow 数据上下文与使用 this.datacontext=this 在代码隐藏中绑定的行为不同?的主要内容,如果未能解决你的问题,请参考以下文章

将Window1图标绑定到MainWindow图标

如何从 WPF 中的另一个窗口绑定到 MainWindow 中的控件?

使用 MVVM 在 MainWindow 上绑定 UserControl 视图模型

为啥在数据模板中使用 xaml UserControl 时无法绑定到依赖属性? [复制]

WPF MVVM ListView动态绑定数据

为啥 WPF/XAML 绑定使用 x:Reference 气质?