【问题标题】:Understanding DataBinding了解数据绑定
【发布时间】:2012-02-16 22:38:04
【问题描述】:

我是 WPF 和整个数据绑定的新手。我读了几篇文章,对如何将我的数据绑定到 UI 元素感到很困惑。

我看到一个帖子是这样做的:

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Name="myWindow">
   <Grid>
       <TextBox Text="{Binding Path=Speed, ElementName=myWindow}" />
   </Grid>
</Window>

这假定Speed 是在代码隐藏文件中定义的属性/成员。其他一些人使用 静态资源 命名绑定,并引用这个和其他名为 DataContext 的人用于绑定。现在,因为我是 WPF 数据绑定的新手,所以我很不确定是否存在任何关于使用哪种数据绑定的最佳实践方法。

基本上我想知道为什么必须有几个类属性定义为底层视图模型的连接器,我虽然这些东西更“动态”。

我的目标是只拥有 XAML 文件,而无需在 *.xaml.cs 代码隐藏文件中添加任何内容。例如:我有一个名为MainWindowViewModel 的类(它将代表我的ViewModel),它有一个ObservableCollection&lt;string&gt; 类型的成员,我想将ListBox(在我的视图中)绑定到这个集合。到目前为止,我完成这项工作的唯一方法是使用第一种情况,ElementName,我必须在视图类中添加一个属性作为一种连接器。就像这样:

MainWindow.xaml:

<Window x:Class="Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Name="MW" Title="MainWindow" Height="419" Width="463">
    <Grid>
        <ListBox ItemsSource="{Binding ElementName=MW, Path=ListerResultConnector}" />
    </Grid>
</Window>

MainWindow.xaml.cs:

private ObservableCollection<string> mListerResultData = MainWindowViewModel.Instance.RetrievalStringResults;
public ObservableCollection<string> ListerResultConnector
{
    get { return mListerResultData; }
}

我的问题是,是否存在一种更智能的方式将数据绑定到我的 UI,作为代码隐藏文件中的进一步“连接器”属性。

【问题讨论】:

标签: c# .net wpf xaml


【解决方案1】:

您的 ViewModel 应设置为视图的 DataContext。那么你在代码隐藏中不需要任何“进一步的连接器”。绑定实际上是指 DataContext,如果你不设置它,它仍然是“this”,它对应于你的代码隐藏文件(这只是你视图的一部分)。

另外,看看:WPF Apps With The Model-View-ViewModel Design Pattern

您应该首先了解 WPF 及其绑定基础知识,但是一旦您了解了这些,我建议您查看 Caliburn Micro 及其基于约定的绑定、事件处理和其他使您的代码更加简洁的功能。

【讨论】:

    【解决方案2】:

    您的{Binding ElementName=MW 表示您正在绑定到窗口本身,因此您的DataContext 是窗口,您实现的任何属性都需要在该窗口中定义(在您的代码后面 - 您的“连接器”中)。

    您需要删除ElementName=MW 位并将您的ViewModel 分配为DataContext,以便您可以直接绑定到它的属性。你如何做到这一点取决于你是使用“ViewModel First”还是“View First”

    首先在 View 中,您在创建视图时手动将 DataContext 分配给代码中的 View。

    首先在 ViewModel 中,您在 XAML 中创建一个 DataTemplate,将您的 View 与特定的 ViewModel 联系起来。我认为 ViewModel first 更常见。 Darjan 发布的链接应该可以帮助您了解其中的区别。

    【讨论】:

    • 感谢您的评论,实际上,在所有帖子的共同帮助下,我得到了它按我想要的方式工作。你让我意识到我将决定如何使用 MVVM 模式,目前我正在使用“View-First”,因为它更容易实现,但我几乎不会考虑设置一些 xaml 模板在将我的视图模型连接到视图时更加动态。非常感谢!
    【解决方案3】:

    您应该使用一个单独的 ViewModel 类 (WindowViewModel),它代表您的 Window (Window.DataContext) 的数据上下文。

    我发现使用MVVM Light toolkit 并关注网站上的一些视频帮助我填补了空白。在开始之前花点时间学习它,它会开始深入人心。IoC containers 还与 MVVM + WPF 混合用于视图模型的目录管理和生命周期管理以及改进的设计时体验(可混合性)。

    工具包不是必需的,有时会妨碍您学习该模式。一旦你理解了它,你应该利用一个工具包来加速开发过程。这是comparison of various MVVM toolkits

    【讨论】:

      【解决方案4】:

      绑定通常有两部分:源对象和属性名

      当您在绑定中指定 ElementName 时,您正在设置 Source 对象。其他指定绑定源对象的方法包括RelativeSourceSource 属性。您也可以不定义绑定的源对象,在这种情况下,它将使用当前对象的DataContext。源对象可以是 WPF 的 VisualTree 中的 UI 元素,也可以是控件的 DataContext 中的类对象

      当您指定Path 时,您是在告诉绑定要使用什么属性。您也可以将此属性留空以绑定到当前对象的DataContext

      DataContext 是存储在控件后面的数据对象。这通常是 ModelViewModel(如果使用 MVVM),尽管它也可以是几乎任何对象,例如 UI 元素。

      在你的例子中

      <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Name="myWindow">
         <Grid>
             <TextBox Text="{Binding Path=Speed, ElementName=myWindow}" />
         </Grid>
      </Window>
      

      您告诉绑定它的源对象是可视树中名为myWindow 的UI 元素,而属性名为Speed。由于您名为 myWindow 的对象属于 Window 类型,因此此绑定仅在您的 Window 类实际上具有名为 Speed 的属性时才有效。

      这里有很多答案建议您改用 MVVM 设计模式,我同意如果您正在使用 WPF,您应该尝试使用 MVVM。它使编码变得更加简单,因为您将应用程序逻辑与 UI 分开。如果您有兴趣,我有一个simple MVVM example posted on my blog,它解释了该设计模式的基础知识。

      【讨论】:

        【解决方案5】:

        最简单的方法是:

        <Window x:Class="WpfApplication4.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:ctrl="clr-namespace:WpfApplication4"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <ctrl:MainWindowViewModel x:Key="mym" />
        </Window.Resources>
        <Grid DataContext="{Binding Source={StaticResource mym}}">
            <ListBox ItemsSource="{Binding Path=MyListProp}" />
        </Grid>
        

        上面的例子做了以下事情:

        1. 为您的窗口创建一个新的 ViewModel 对象作为资源
        2. 将视图模型分配为窗口的 DataContext(对于根网格更精确)
        3. 将列表框绑定到您的 ViewModel ObservableCollection 属性 MyListProp。

        通过使用msdn库,尝试熟悉绑定类的属性以充分理解本示例。 WPF 4 Unleashed - Adam Nathan 也是 wpf 初学者的绝佳资源。第 13 章 - 数据绑定应该涵盖您可能想了解的有关绑定的所有内容。

        【讨论】:

          【解决方案6】:

          是的,如果不混淆,绑定就不算什么。

          This example from msdn 可能会有所帮助。请注意DataContext 是如何在Window“级别”声明的——在这种情况下它是一个复杂/复合对象,因此窗口子元素的{Binding} 声明隐含地相对于“父级别”DataContext

          我们得到的主要好处是,当DataContext 设置为给定对象时,所有“子元素”数据绑定都会自动保持同步。通过使用这种模式,我们可以在 UI 控制结构层次结构中的任何/多个级别控制这种同步。

          集合绑定

          底线是您的收藏必须至少实现IList。许多 .NET Collection 类“已准备好绑定”。

          这是msnd doc on ObservableCollection的引述:

          在实现您自己的集合之前,请考虑使用 ObservableCollection 或现有集合类之一,例如 List、Collection 和 BindingList 等。如果您有一个高级场景并希望实现自己的集合,请考虑使用 IList,它提供了一个非泛型对象集合,可以通过索引单独访问。实现 IList 可为数据绑定引擎提供最佳性能。

          最后,2路绑定需要IBinding list vs IList

          【讨论】:

            猜你喜欢
            • 2017-05-03
            • 1970-01-01
            • 2020-08-27
            • 2018-03-17
            • 1970-01-01
            • 2013-02-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多