【问题标题】:WPF binding multiple controls to different datacontextsWPF 将多个控件绑定到不同的数据上下文
【发布时间】:2010-10-15 08:41:06
【问题描述】:

我有一个场景,我真的不知道如何将数据绑定到托管在 UserControl 中的控件到多个数据上下文。

我要绑定的数据来自 2 个类

UserInfo, UserExtendedInfo

UserControl 的数据上下文设置为 UserInfo,因此我可以轻松地绑定大多数控件,执行以下操作

<Label Name="LblEmail" Text="{Binding Email}" />

但是我不知道如何轻松地绑定来自 UserExtendedInfo 类的属性。我最初的想法是设置每个想要使用来自 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

【问题讨论】:

    标签: .net wpf data-binding resources


    【解决方案1】:

    这就是 M-V-VM 派上用场的地方。这个想法(至少据我所知......对我来说仍然很新)是 Window 本身绑定到“ViewModel”类。 ViewModel 类只是一个代表所有数据的类,您的整个页面可以访问它需要的所有内容......它只是将您需要绑定到的所有不同对象汇集到一个类中......并且您将 Window(或 Page)的 DataContext 设置为此类的一个实例。您的 UserInfo 和 UserInfoExtended 实例是 ViewModel 对象的公共属性,您只需使用绑定元素的 Path 即可通过您希望将每个控件绑定到的适当对象的适当属性。

    有一个很棒(但很长)的视频解释了这种模式,它通过一个完整的示例说明了实现这一点的许多方法以及为什么这是一个在 WPF 应用程序中使用的方便且可扩展的模型的许多不同原因。它还涵盖了 WPF 的许多功能以及对依赖注入的介绍,这些都是非常相关的主题,给出了示例。

    这是博客文章的链接,其中包含我正在谈论的视频的链接:

    编辑:博客文章已被删除(这个答案已经很老了)。这是 YouTube 上的视频:

    https://www.youtube.com/watch?v=BRxnZahCPFQ

    【讨论】:

    • 请注意,ViewModel 不需要依赖属性。如果您希望控件反映其属性之一的更改,它只需要实现 INotifyPropertyChanged。
    • @HassanTareq 在 YouTube 上找到并更新了链接
    【解决方案2】:

    这是最简单的方法,效果很好。

    在您设置上下文的代码隐藏中,只需使用包含所有所需值的匿名类型:

    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}">
          ...
    

    【讨论】:

    • 谢谢!帮了我很多忙!
    • 但是你能在后面的代码中更改那些匿名属性值吗?这看起来像是一次性初始化。
    【解决方案3】:

    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 完全隔离可能在架构上更可取,从而消除了对绑定路径的需求。

    【讨论】:

    • 这是对 bendeway 的回答 (+1) 的改进,但我会改进一些其他事情:您不需要“Path=”,在 95% 的情况下我会使用 C# 匿名类型而不是显式类。
    【解决方案4】:

    我可能会考虑将您的用户对象包装在一个单独的类中,然后设置包含数据的子面板的 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 属性

    【讨论】:

    • 好吧,这很有意义。在 WPF 中要学习很多新东西 :)
    • 与其创建一个仅用于支持此特定视图的新模型,不如将 UserInfo 和 UserExtendedInfo 添加为可以绑定到视图的 ViewModel 的公共属性。 (参见 Rich 的 answer)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 2016-10-03
    相关资源
    最近更新 更多