wpf 为什么在 XAML 中绑定 MainWindow 数据上下文无法与使用 this.datacontext=this 在代码隐藏中绑定相同?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15205280/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:51:14  来源:igfitidea点击:

Why does binding the MainWindow datacontext in XAML fail to act the same as binding in the codebehind with this.datacontext=this?

c#wpfxamldata-binding

提问by Hydronium

I am trying to use Data binding to bind an ObservableCollection to the ItemsSource of a DataGrid, as I learn about WPF and stuff.

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

In the code-behind I can set the DataContext with this.DataContext = this;or bloopDataGrid.DataContext = this;. That's fine and dandy.

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

I thought I could try something like

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

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

in my main window, but this causes a Stack Overflow Exception as explained in this question. Fine, that makes some sense.

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

After reading thisand other questions/answers that say to try DataContext="{Binding RelativeSource={RelativeSource Self}}"in the window's XAML code, I thought I could actually do this. Apparently I cannot. Or at least, the IDE lets me and it's syntactically correct, but does not do what I want (ie, exactly what this.DataContext = this;does).

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

Then I read thisabout using "{Binding ElementName=, Path=}"and tried to use it like so:

然后我阅读有关使用的内容"{Binding ElementName=, Path=}"并尝试像这样使用它:

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

Which also doesn't work. Maybe not for the same reason, but I can't figure out the problem with it.

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

Oddly, I can't replicate the rebinding example shown in Rachel Lim's blog post.

奇怪的是,我无法复制Rachel Lim 的博客文章中显示的重新绑定示例。

XAML:

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#:

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

    }
}

The above code is what I'm using to test this, and is currently using the code-behind version which correctly gives me

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

In codebehind

在代码隐藏中

What am I doing wrong, which is preventing me from getting the same results as the above picture but by using XAML for the DataContext handling? Am I not connecting the dots properly? ...am I missing some dots?

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

回答by Federico Berasategui

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

is not the same as

不一样

this.DataContext = this;

The first one is creating a new instance of the MainWindowclass and assigning that to the DataContextproperty of the Window, while the second is assigning the very same instance of the Windowto its DataContextproperty.

第一个是创建类的新实例MainWindow并将其分配给 的DataContext属性Window,而第二个是将 的完全相同的实例分配Window给其DataContext属性。

In order to achieve that in XAML, you need to use a RelativeSourceBinding:

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

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

Edit:

编辑:

The difference in behavior between defining the DataContextin XAML and in code behind is caused by the fact that the XAML is actually parsed when the constructor finishes executing, because the Dispatcherwaits for the user code (in the constructor of the Window) to finish before executing its pending operations.

定义DataContextin XAML 和 in code behind之间的行为差​​异是由于在构造函数完成执行时实际上解析了 XAML,因为Dispatcher在执行其之前等待用户代码(在 Window 的构造函数中)完成待处理的操作。

This causes the actual property values to be different in these different moments, and since there is no INotifyPropertyChanged, WPF has no way of updating the UI to reflect the new values.

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

You couldimplement INotifyPropertyChangedin the Windowitself, but I suggest creating a ViewModel for this, as I don't like the fact of mixing INotifyPropertyChanged(which is more of a ViewModel concept) with DependencyObject-derived classes (UI elements).

could实现INotifyPropertyChangedWindow本身,但我建议创建一个视图模型为这一点,因为我不喜欢混合的事实INotifyPropertyChanged(这更像是一个视图模型的概念)与DependencyObject派生类(UI元素)。