Window DataContext or ElementName

本文关键字:ElementName or DataContext Window | 更新日期: 2023-09-27 18:28:07

我目前在指定或不指定窗口的数据上下文方面遇到了一个小问题,以及为什么各种方法之间存在差异。希望你能帮我。

让我们从一些代码开始展示我的问题。这是我的TestWindow.xaml.cs的代码,没有什么特别的,只是一个简单的字符串属性

public partial class TestWindow : Window
{
    private string _helloWorld = "Hello World!";
    public string HelloWorld
    {
        get { return _helloWorld; }
        set { _helloWorld = value; }
    }
    public TestWindow()
    {
        InitializeComponent();
    }
}

此代码对于以下3个XAML布局都是相同的,因此仅在XAML中代码后面没有任何更改。

1.)具有给定ElementName 的数据绑定

<Window x:Class="Ktsw.Conx.ConxClient.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestWindow" Height="300" Width="300"
        Name="TestWin">
    <Grid>
        <TextBlock Text="{Binding HelloWorld, ElementName=TestWin}"></TextBlock>
    </Grid>
</Window>

2.)在Window 上指定DataContext的数据绑定

<Window x:Class="Ktsw.Conx.ConxClient.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestWindow" Height="300" Width="300"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <TextBlock Text="{Binding HelloWorld}"></TextBlock>
    </Grid>
</Window>

3.)既没有ElementName也没有指定DataContext

<Window x:Class="Ktsw.Conx.ConxClient.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestWindow" Height="300" Width="300">
    <Grid>
        <TextBlock Text="{Binding HelloWorld}"></TextBlock>
    </Grid>
</Window>

前两种方法效果不错,但为什么第三种方法失败了?

在第一个方法中,我没有指定DataContext,它自动工作,在第二个方法中我没有指定ElementName,它工作,但没有声明其中一个,它失败了。为什么它不能自动获得两者,但单独获得两者都很好?

Window DataContext or ElementName

阅读Binding.Source属性的备注。绑定源是要在其上查找Path(HelloWorld)指定的属性的对象。ElementNameRelativeSourceSource设置绑定源。如果它们为null,则源为要绑定的元素(TextBlock)的DataContext。如果没有显式设置元素的DataContext,则它是从包含元素继承的。

在第一种情况下,任何DataContext都与TextBlock绑定无关,因为源是通过ElementName显式设置的。

在第二种情况下,指定源需要DataContext,因为它不是通过ElementName、RelativeSource或source显式设置的。未设置TextBlock的DataContext,因此继承了Window的。

在第三种情况下,没有显式源,也没有要继承的DataContext,因此源为null,绑定失败。没有默认来源。

默认情况下,{Binding}总是指DataContext

在第一个示例中,您只需使用elementName来停用默认行为,然后将该元素用作源。

在第二个示例中,您明确地将DataContext更改为指向您的Window。

因此,在最后一个示例中,{Binding HelloWorld}尝试将null转换为具有HelloWorld属性的对象,但失败了。

它在第一种和第二种情况下都有效,因为TextBlock能够找到HelloWorld属性

在第一种情况下,您指定的是ElemtnName,因此TextBlock将引用Window并在Window类中搜索属性HelloWorld

在第二种情况下,您正在指定Window的DataContext,因此Textblock将继承该属性,并在DataContext中查找HelloWorld属性,即再次查找Window

在第三种情况下,您没有指定任何内容,因此TextBlock无法找到HelloWorld属性

在第一种情况下,我没有指定DataContext,为什么它应该知道得到什么?

当您设置ElementName时,TextBlock将尝试从元素中查找HelloWorld

在第二种情况下,我没有具体说明它应该得到什么?

您正在设置它的父级DataContext,即Window,以便它自动继承它,并告诉它从DataContext 中提取HelloWorld属性

第三个失败,因为DataContext不是推断的如果你想让第三个工作,你可以这样做:

public TestWindow()
{
    InitializeComponent();
    this.DataContext = this;
}

它对路径HelloWorld一无所知,因为它没有DataContext