14

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

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

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

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

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

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

然后我读了这篇关于使用的文章"{Binding ElementName=, Path=}"并尝试像这样使用它:

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

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

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

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 处理?我没有正确连接点吗?...我错过了一些点吗?

4

1 回答 1

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

不一样

this.DataContext = this;

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

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

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

编辑:

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

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

您自己could实现INotifyPropertyChangedWindow但我建议为此创建一个 ViewModel,因为我不喜欢将INotifyPropertyChanged(这更像是一个 ViewModel 概念)与DependencyObject派生类(UI 元素)混合的事实。

于 2013-03-04T15:44:59.573 回答