【问题标题】:Can't wrap my head around wpf databinding无法围绕 wpf 数据绑定
【发布时间】:2010-10-27 08:55:22
【问题描述】:

我的场景: wpf 表单有一个文本框和一个 wpf 工具箱datagrid。 在文本框中输入文本时,我的服务会返回 IEnumerable<TranslationItem> 项目。我希望我的数据网格显示此服务的结果。

我尝试用谷歌搜索,但我无法得到正面或反面。我才刚刚开始学习 WPF,大多数使用过的术语都让我无法理解。
我收集到的是我应该把我的服务结果放在一个 ObservableCollection 中,不费吹灰之力。 但后来我想以某种方式将它绑定到我的数据网格。我怎样才能做到这一点?网格如何知道要生成哪些列?

【问题讨论】:

    标签: .net wpf data-binding observablecollection


    【解决方案1】:

    我收集到的是,我应该将我的服务结果放入 ObservableCollection,毫不费力。但后来我想以某种方式将它绑定到我的数据网格。我该怎么做?

    最简单的方法是将 DataGrid 的 ItemsSource 属性设置为 ObservableCollection。

    网格如何知道要生成哪些列?

    DataGrid 反映该集合中的对象,并为它找到的每个公共属性创建一个列。请参阅here 了解更多信息。

    如果您直接设置 ItemsSource 属性,那么它并不是真正的 wpf 绑定。当我开始在 WPF 中进行数据绑定时,我发现以下三个链接很有用。

    Bea Stollnitz: What does “{Binding}” mean?
    WPF Basic Data Binding FAQ
    MSDN: Data Binding How-to Topics

    【讨论】:

    • 看来这里有一些不错的读物。现在没有时间检查它们,但我有时间会回来。
    【解决方案2】:

    虽然可以为此使用 ObservableCollection,但取决于它的使用方式,您不会从中获得任何好处。 ObservableCollection 的关键特性是它实现了 INotifyCollectionChanged。这个接口的作用是提供一个通知机制来告诉 UI 一个属性已经改变。由于 ObservableCollection 已经实现了这一点,如果您将 DataGrid、ListBox、ItemsControl 等的 ItemSource 属性绑定到此类型的集合,它将在任何时候添加/删除/替换/移动/重置项目时自动更新 UI。因此,每次您想使用新的 IEnumerable 结果集更新集合时,都必须先清除集合,然后再添加新结果。

    但是,在这种情况下,我会推荐另一个选项而不是 ObservableCollection。它是使用一个叫做 ObjectDataProvider 的东西。使用它我们可以完全避免后面的代码,并且它整体上更干净。所以我们在某个地方有我们的服务,在本例中是在我的 Window.xaml.cs

    public class TranslationService
    {
        public IEnumerable<string> Translate(string s)
        {
            return s.ToCharArray().Select(c => c.ToString());
        }
    }
    

    就像您描述的服务一样,它从文本框中获取一个字符串,并返回一个 IEnumerable。现在,在 XAML 中,我们可以使用该服务并对其进行调用。

    在窗口声明中,我们为服务所在的位置添加命名空间:

     xmlns:local="clr-namespace:WpfApplication4"
    

    现在,在我们的 Window.Resources(或 UserControl,或其他任何地方)中,我们可以引用我们的服务。一旦我们将服务公开为资源,我们就可以创建一个 ObjectDataProvider 来公开我们希望使用的 Translate 方法。

    <Window.Resources>
        <local:TranslationService x:Key="MyTranslationService" />
        <ObjectDataProvider x:Key="MyProvider"
                            ObjectInstance="{StaticResource MyTranslationService}"
                            MethodName="Translate">
            <ObjectDataProvider.MethodParameters>
                ""
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
    

    ObjectDataProvider 与我们的 Service 绑定,并使用 String 参数调用 Translate 方法。现在我们要做的就是让它响应我们的文本框。

    我们可以通过使用一些 Binding 属性来做到这一点。我们希望 TextBox 中的 TextProperty 绑定到 ObjectDataProvider,因此我们将 Source 属性设置为指向它。我们要在 Path 中绑定的 ObjectDataProvider 部分是 MethodParameter。现在,我们将它设置为直接绑定到该属性的源,并且只移动一种方式,这意味着 ObjectDataProvider 的方法参数不会更新 TextBox 的文本。最后,我们可以将 UpdateSourceTrigger 设置为 PropertyChanged,告诉绑定在对象数据提供程序中设置我们绑定到的源,只要文本有任何更改。

    <StackPanel>
            <TextBox TextChanged="OnTextChanged"
                Text="{Binding Source={StaticResource MyProvider}, Path=MethodParameters[0], BindsDirectlyToSource=True, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
            <ListBox ItemsSource="{Binding Source={StaticResource MyProvider}}" />
        </StackPanel>
    

    剩下的就是在 Grid 中设置 ItemsSource,或者在本例中设置一个简单的 ListBox。

    关于 DataGrid 的最后一部分: 如果您使用的是 WPFToolkit 的数据网格,它确实具有可以通过属性设置的自动生成功能,您可以在 here 找到更多信息。

    【讨论】:

    • 谢谢,我想我可以应用这个例子,只需稍加改动。我不会直接调用我的服务,因为我不希望每次击键都会触发对我的服务(以及我的翻译数据库)的调用,而是在两者之间有一个小定时器缓冲区。但除此之外,它看起来很有希望。
    【解决方案3】:

    您将网格的 DataSource(甚至是 DataContext)设置为您的 Observable Collection。

    我不熟悉该数据网格,但大多数网格都可以选择将 Observable Collection 中该类型的所有公共属性公开为列,或者您在 XAML 中显式设置列布局以及列定义是用于列数据的对象的属性。

    例如使用 Infragistics 数据网格

                    <igDP:Field Name="OrderSize" Label="Order Size">
                        <igDP:Field.Settings >
                            <igDP:FieldSettings CellWidth="75">
                                <igDP:FieldSettings.EditorStyle>
                                    <Style TargetType="{x:Type Editors:ValueEditor}" >
                                        <Style.Setters>
                                            <Setter Property="Format" Value="#,##0"/>
                                        </Style.Setters>
                                    </Style>
                                </igDP:FieldSettings.EditorStyle>
                            </igDP:FieldSettings>
                        </igDP:Field.Settings>
                    </igDP:Field>
    

    名称是您在要使用的对象上设置属性的位置。

    【讨论】:

      【解决方案4】:

      您的网格可以直接构建列,也可以指定您希望的列类型。如果你看这个video,它会解释它。这适用于 VS2010,但基本原理与 VS2008 相同——尽管实现方式略有不同,因为它没有完全集成。

      至于如何绑定,将保存您的项目的 ObservableCollection 分配给网格的 ItemsSource 属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-02
        • 1970-01-01
        • 2017-01-10
        • 1970-01-01
        相关资源
        最近更新 更多