我有一个场景,我真的不知道如何将数据绑定到UserControl托管的控件到多个datacontexts。
我想绑定的数据来自2个类
UserInfo, UserExtendedInfo
UserControl的datacontext设置为UserInfo,因此我可以轻松绑定大多数控件执行以下操作
<Label Name="LblEmail" Text="{Binding Email}" />
但是我不知道如何轻松地绑定UserExtendedInfo类中的属性。我最初的想法是设置每个控件的datacontext,以便使用UserExtendedInfo中的数据,这样我就可以这样做。但这似乎很麻烦,因为我必须手动分配每个人。每次UserControl变得可见时,必须从数据库中获取UserExtendedInfo的数据,以使其不会失去同步。
XAML:
<Label Name="LblTest" Text="{Binding Locale}" />
代码背后:
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
答案 0 :(得分:29)
我可能会想到将用户对象包装在一个单独的类中,然后设置包含数据的子面板的DataContext属性。
例如:
public class UserDataContext
{
public UserInfo UserInfo { get; set; }
public UserExtendedInfo UserExtendedInfo { get; set; }
}
然后在 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>
这假设您的UserInfo类具有Email
属性和
您的UserExtendedInfo类具有Locale和AboutMe
的属性答案 1 :(得分:19)
这是最简单的方法,而且效果很好。
在设置上下文的代码隐藏中,只需使用包含所有所需值的匿名类型:
DataContext = new
{
info = FetchUserInfoFromDatabase(),
extendedInfo = FetchExtendedUserInfoFromDatabase(),
};
在XAML中,您可以绑定任何内容:
<UserControl>
<StackPanel>
<TextBlock Text="{Binding info.Email}" />
<TextBlock Text="{Binding extendedInfo.Locale} />
...
或者,您可以按照其他答案描述的两个级别进行绑定:
<UserControl>
<StackPanel>
<Grid DataContext="{Binding info}">
<TextBlock Text={Binding Email}">
...
答案 2 :(得分:8)
这是M-V-VM非常方便的地方。这个想法(至少我理解它......对我来说还是一个新东西)是Window本身被绑定到一个“ViewModel”类。 ViewModel类只是一个类,它以一种整个页面可以访问所需内容的方式表示所有数据......它只是将您需要绑定的所有不同对象集中在一个类中......您将Window(或Page)的DataContext设置为此类的实例。您的UserInfo和UserInfoExtended实例是ViewModel对象的公共属性,您只需使用绑定元素的Path来通过您希望将每个控件绑定到的相应对象的相应属性。
有一个很棒的(但很冗长的)视频解释了这个模式,它通过一个完整的例子说明了实现这个的许多方法,以及为什么这是一个在WPF应用程序中使用的方便和可扩展的模型的许多不同原因。它还涵盖了WPF的许多功能以及依赖注入的介绍,这些都是非常相关的主题,给出了这个例子。
这是博客帖子的链接,其中包含我所说的视频的链接:
编辑:博客文章已被删除(此答案相当陈旧)。以下是YouTube上的视频:
答案 3 :(得分:7)
Rich和bendewey都有很好的答案。今天在Silverlight而不是WPF中探索这个相同的主题,我发现没有必要建立多个DataContexts。修改bendewey的例子:
<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>
使用绑定路径,您可以灵活地将绑定混合和匹配到不同类的属性,而无需考虑控件容器的DataContext。
您还可以通过添加操作UserInfo和UserExtendedInfo类属性的属性来扩展bendewey的UserDataContext类的功能。例如,您可以组合名字和姓氏。
您可能希望实现INotifyPropertyChanged,以便在重置UserInfo和UserExtendedInfo时更新控件。
通过在UserDataContext中直接公开所需的属性,从而消除对绑定路径的需要,在结构上优先将底层的UserInfo和UserExtendedInfo类与XAML隔离开来。