DataContext是用来做什么的?

39
作为问题Linking DataContext with another property in WPF的延续。
在研究的最后,我非常惊讶地发现,当一个人像这样写入内容时:
<Label Content="{Binding Path=Name}" />

Content属性绑定的DataContextLabel控件本身!它仍然有效的原因是由于默认从最近父级继承DataContext值。

但如果您将此标签包装在自定义控件中,并且不希望将数据绑定到该控件的DataContext属性,您更可能希望:

<Controls:SearchSettings Settings="{Binding Path=Settings}" />

现在你需要将Settings设置为SearchSettings控件的DataContext,以便内部的Label进行绑定,但你不能这样做,因为那会触发Settings属性的重新绑定。

我不明白为什么要混淆使用不同数据源的绑定属性:如DataContextElementName等。那么我为什么还要使用DataContext呢?

4个回答

108

当你写代码时

<Label name="myLabel" Content="{Binding Path=Name}" />

你正在绑定到myLabel.DataContext.Name,而不是myLabel.Name

在WPF中,XAML只是一个漂亮的用户界面,用于显示和与实际数据交互,也就是DataContext。其他绑定源(例如RelativeSourceElementName等)的目的是指向另一个属性,该属性不存在于当前控件的DataContext中。


假设有一个窗口。如果没有设置DataContext,则窗口仍会显示,但其后面没有数据。

现在假设设置了myWindow.DataContext = new ClassA();。现在窗口显示的数据是ClassA。如果ClassA有一个名为Name的属性,我可以编写一个标签并将其绑定到Name(例如您的示例),无论存储在ClassA.Name中的值是什么,都会被显示。

现在,假设ClassA有一个ClassB属性,并且两个类都有一个叫做Name的属性。以下是一段XAML代码块,说明了DataContext的目的,并展示了如何引用自己的DataContext中不存在的属性。

<Window x:Name="myWindow"> <!-- DataContext is set to ClassA -->
    <StackPanel> <!-- DataContext is set to ClassA -->

        <!-- DataContext is set to ClassA, so will display ClassA.Name -->
        <Label Content="{Binding Name}" />

         <!-- DataContext is still ClassA, however we are setting it to ClassA.ClassB -->
        <StackPanel DataContext="{Binding ClassB}">

            <!-- DataContext is set to ClassB, so will display ClassB.Name -->
            <Label Content="{Binding Name}" />

            <!-- DataContext is still ClassB, but we are binding to the Window's DataContext.Name which is ClassA.Name -->
            <Label Content="{Binding ElementName=myWindow, Path=DataContext.Name}" /> 
        </StackPanel>
    </StackPanel>
</Window>

正如您所看到的,DataContext基于UI对象后面的任何数据。

更新:我经常从新的WPF用户那里看到这个问题,因此我将这个答案扩展为我的博客文章:“DataContext”是什么?


嗨!感谢您详细的回答。但是,我不喜欢您示例中的一点,那就是您绑定了DataContext属性本身。在您的示例中,我很可能会将StackPanel提取到单独的控件中。如果它的DataContext只是其父级DataContext的隔离部分,那么这是有意义的,不是吗?然后,我不会绑定我的用户控件的DataContext属性,而是会有一个具有自我描述性名称的特殊属性。(我的意思是特定控件的DataContext是什么?我应该传递什么?)这就是事情变得复杂的地方。[待续] - Eugene Strizhok
但是这样做将会打破控件本身的绑定,因为正如你所指出的那样,当编写Content={Binding Name}时,它绑定到了Label.DataContext.Name而不是我希望它执行的Label.Parent.DataContext.Name - Eugene Strizhok
6
@Eugene 我强烈建议你研究MVVM设计模式。在我看来,它应该与任何WPF应用程序一起使用,并且你将更好地理解DataContext及其重要性。你的可视化控件并不是你的应用程序 - 你的DataContext(ViewModels)才是。可视化控件(标签、按钮、文本框等)只是一个漂亮的UI,让用户与你的应用程序进行交互。 - Rachel
你在博客上写的那篇文章非常棒,强烈推荐! - Avi
这是一个非常好的答案。99%的WPF教程存在的问题是它们甚至没有试图解释内部发生了什么。我是一名程序员,我需要理解内部!花了我一段时间才意识到XAML以某种方式被转换为类(尽管我仍然不知道如何)。 - Clonkex
显示剩余2条评论

3

来自 kishore Gaddam 的 CodeProject

DataContext 是数据绑定中最基本的概念之一。绑定对象需要从某个地方获取其数据,有几种方法可以指定数据源,例如在绑定中直接使用 Source 属性、在树形结构中向上遍历时从最近的元素继承 DataContext、在绑定对象中设置 ElementNameRelativeSource 属性。

在 CodeProject 上有详细的例子:http://www.codeproject.com/Articles/321899/DataContext-in-WPF


1
在这种情况下,您可以这样做:
<Controls:SearchSettings DataContext="{Binding Path=Settings}" Settings="{Binding}" />

假設您希望所有可能成為 SearchSettings 內容的東西都使用 Settings 作為其資料上下文。基本上,DataContext 影響元素本身和任何沒有明確覆蓋它的後代。

1
在大多数情况下,您确实希望绑定到DataContext,在ItemsControls上的某些模板中,这是绑定到当前模板化项的唯一方法。此外,对DataContext的进一步绑定很容易编写和阅读,因为它们简洁明了。
在您的示例中,您仍然可以设置DataContext,只需要相应地修改Settings上的绑定即可:
<Controls:SearchSettings DataContext="{Binding Settings}" Settings="{Binding}"/>

我曾考虑过这种方法,但它没有意义。如果我只需要一个属性,为什么要绑定两个属性呢? - Eugene Strizhok
@EugeneStrizhok:你不仅需要一个,这样可以让你绑定到子控件中的设置而不必设置源,因为现在可以使用DataContext。 - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接