.net WPF 将多个控件绑定到不同的数据上下文
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/679933/
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
WPF binding multiple controls to different datacontexts
提问by Alex
I have a scenario where I don't really know how to bind data to controls hosted in a UserControl to multiple datacontexts.
我有一个场景,我真的不知道如何将数据绑定到托管在 UserControl 中的控件到多个数据上下文。
The data i want to bind comes from 2 classes
我要绑定的数据来自 2 个类
UserInfo, UserExtendedInfo
The datacontext of the UserControl is set to UserInfo so i can bind most controls easily doing the following
UserControl 的数据上下文设置为 UserInfo,因此我可以轻松地绑定大多数控件,执行以下操作
<Label Name="LblEmail" Text="{Binding Email}" />
However I don't know how to bind properties from the UserExtendedInfo class easily. My initial thought was to set the datacontext of each control that want's to use the data from UserExtendedInfo so i could do the same. But this seems cumbersome as i would have to manually assign each one indivdually. The data for UserExtendedInfo must be fetched from the database each time the UserControl becomes visible so that it doesn't get out of sync.
但是我不知道如何轻松地从 UserExtendedInfo 类绑定属性。我最初的想法是设置想要使用 UserExtendedInfo 数据的每个控件的数据上下文,以便我可以这样做。但这似乎很麻烦,因为我必须单独手动分配每个。每次 UserControl 变得可见时,都必须从数据库中提取 UserExtendedInfo 的数据,以免它不同步。
XAML:
XAML:
<Label Name="LblTest" Text="{Binding Locale}" />
Code Behind:
背后的代码:
Private Sub UserManager_IsVisibleChanged(ByVal sender As System.Object, ByVal e As System.Windows.DependencyPropertyChangedEventArgs)
If DirectCast(e.NewValue, Boolean) Then
Dim user As UserInfo = DirectCast(DataContext, UserInfo)
If user IsNot Nothing Then
Dim usrExt As UserExtenedInfo = UserController.GetUserExtended(user.userID)
LblTest.DataContext = usrExt
Else
Throw New ArgumentException("UserId doesn't exist or is less than 1")
End If
End If
End Sub
回答by bendewey
I would maybe think about wrapping your user object in a seperate class then setting the DataContext properties of sub-panels that contain the data.
我可能会考虑将您的用户对象包装在一个单独的类中,然后设置包含数据的子面板的 DataContext 属性。
For example:
例如:
public class UserDataContext
{
public UserInfo UserInfo { get; set; }
public UserExtendedInfo UserExtendedInfo { get; set; }
}
Then in your UserControl.xaml:
然后在您的UserControl.xaml 中:
<!-- Binding for the UserControl should be set in its parent, but for clarity -->
<UserControl DataContext="{Binding UserDataContext}">
<StackPanel>
<Grid DataContext="{Binding UserInfo}">
<TextBlock Text="{Binding Email}" />
</Grid>
<Grid DataContext="{Binding UserExtendedInfo}">
<TextBlock Text="{Binding Locale}" />
<TextBlock Text="{Binding AboutMe}" />
</Grid>
</StackPanel>
</UserControl>
This assumes that your UserInfo class has a property of Email
这假设您的 UserInfo 类具有 Email 属性
and
和
That your UserExtendedInfo class has a property of Locale and AboutMe
您的 UserExtendedInfo 类具有 Locale 和 AboutMe 属性
回答by Ray Burns
Here is the simplest method of all, and it works very well.
这是最简单的方法,而且效果很好。
In the code-behind where you set the context, simply use an anonymous type containing all the desired values:
在设置上下文的代码隐藏中,只需使用包含所有所需值的匿名类型:
DataContext = new
{
info = FetchUserInfoFromDatabase(),
extendedInfo = FetchExtendedUserInfoFromDatabase(),
};
In the XAML you can bind to anything:
在 XAML 中,您可以绑定到任何内容:
<UserControl>
<StackPanel>
<TextBlock Text="{Binding info.Email}" />
<TextBlock Text="{Binding extendedInfo.Locale} />
...
Alternatively you can bind in two levels as other answers have described:
或者,您可以像其他答案所描述的那样绑定两个级别:
<UserControl>
<StackPanel>
<Grid DataContext="{Binding info}">
<TextBlock Text={Binding Email}">
...
回答by Rich
This is where M-V-VM comes in very handy. The idea (as I understand it at least...still very new to me) is that the Window itself is bound to a "ViewModel" class. The ViewModel class is just a class that represents all the data in a way that your entire page has access to everything it needs...it simply brings together all the different objects you'll need to bind to in one class...and you set the DataContext of the Window (or Page) to an instance of this class. Your UserInfo and UserInfoExtended instances are public properties of the ViewModel object, and you just use the Path of your binding element to get you through the appropriate properties of the appropriate objects you wish to bind each control to.
这就是 MV-VM 派上用场的地方。这个想法(至少据我所知......对我来说仍然很新)是窗口本身绑定到“ViewModel”类。ViewModel 类只是一个类,它以一种方式表示所有数据,您的整个页面都可以访问它需要的所有内容……它只是将您需要绑定到的所有不同对象集中到一个类中……并且您将窗口(或页面)的 DataContext 设置为此类的实例。您的 UserInfo 和 UserInfoExtended 实例是 ViewModel 对象的公共属性,您只需使用绑定元素的 Path 来获取您希望将每个控件绑定到的适当对象的适当属性。
There's a great (but quite lengthy) video explaining this pattern, and it goes through a full example that illustrates many ways to accomplish this and many different reasons why this is a convenient and scalable model to use in a WPF app. It also covers many features of WPF as well as an introduction to dependency injection, which are very relevant topics as well, given the example.
有一个很好的(但很长)视频解释了这种模式,它通过一个完整的示例说明了实现这一点的多种方法以及许多不同的原因,为什么这是一个在 WPF 应用程序中使用的方便且可扩展的模型。它还涵盖了 WPF 的许多功能以及依赖注入的介绍,给出了示例,这些也是非常相关的主题。
Here's a link to the blog post which contains a link to the video I'm speaking of:
这是博客文章的链接,其中包含指向我所说的视频的链接:
EDIT: Blog post has been removed (this answer is quite old). Here is the video on YouTube:
编辑:博客文章已被删除(这个答案很旧)。这是 YouTube 上的视频:
回答by BillVo
Both Rich and bendewey had good answers. Exploring this same topic today in Silverlight instead of WPF, I found that it's not necessary to establish multiple DataContexts. Revising bendewey's example:
里奇和本德威都给出了很好的答案。今天在 Silverlight 而不是 WPF 中探索相同的主题,我发现没有必要建立多个 DataContexts。修改本德威的例子:
<UserControl DataContext="{Binding UserDataContext}">
<StackPanel>
<TextBlock Text="{Binding Path=UserInfo.Email}" />
<TextBlock Text="{Binding Path=UserExtendedInfo.Locale}" />
<TextBlock Text="{Binding Path=UserExtendedInfo.AboutMe}" />
</StackPanel>
</UserControl>
Using the Binding Path you gain the flexibility to mix and match bindings to properties of different classes without concern for the DataContext of the controls' containers.
使用绑定路径,您可以灵活地混合和匹配不同类的属性的绑定,而无需考虑控件容器的 DataContext。
You can also extend the capabilities of bendewey's UserDataContext class by adding properties that manipulate properties of the UserInfo and UserExtendedInfo classes. You might, for example, combine first name and last name.
您还可以通过添加操作 UserInfo 和 UserExtendedInfo 类的属性的属性来扩展本德维的 UserDataContext 类的功能。例如,您可以组合名字和姓氏。
You may wish to implement INotifyPropertyChanged so that your controls update when you reset UserInfo and UserExtendedInfo.
您可能希望实现 INotifyPropertyChanged,以便在您重置 UserInfo 和 UserExtendedInfo 时更新您的控件。
It may be architecturally preferable to entirely isolate the underlying UserInfo and UserExtendedInfo classes from the XAML by exposing the required properties directly in UserDataContext, thereby eliminating the need for Binding Path.
通过直接在 UserDataContext 中公开所需的属性,从 XAML 中完全隔离底层 UserInfo 和 UserExtendedInfo 类可能在体系结构上更可取,从而消除对绑定路径的需要。

