【问题标题】:WPF DataGrid: How do I databind the properties of the SelectedItem to trigger INotifyPropertyChangedEvents?WPF DataGrid:如何对 SelectedItem 的属性进行数据绑定以触发 INotifyPropertyChangedEvents?
【发布时间】:2011-04-22 12:34:39
【问题描述】:

我正在尝试尽可能将其作为 MVVM:
我的模型 (InterestTypeEntity) 实现了 INotifyPropertyChanged。
我的 ViewModel (InterestTypeAllViewModel) 有一个绑定到 DataGrid 的 ObservableCollection。当对其进行更改时,它将这些更改(添加/删除)发送到数据库。

问题是,当集合内对象的属性发生变化时,我还希望能够更新数据库。我不知道该怎么做?到目前为止,这是我的代码...

XAML:

<DataGrid Name="TestGrid" Grid.Row="3" Grid.ColumnSpan="2" AutoGenerateColumns="False"
          ItemsSource="{Binding IntTypes}" SelectedItem="{Binding CurrentIntType}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Interest ID" Binding="{Binding IntType}" />
        <DataGridTextColumn Header="Interested Parties Description" Binding="{Binding Description}" MaxWidth="500" />
    </DataGrid.Columns>
</DataGrid>

ViewModel 代码:

public ObservableCollection<InterestTypeEntity> IntTypes 
{
    get { return DataRepository.InterestTypeEntities; }
}

public InterestTypeEntity CurrentIntType { get; set; }

public Int16 IntType
{
    get { return CurrentIntType.IntType; }
    set
    {
        if (value != CurrentIntType.IntType)
        {
            CurrentIntType.IntType = value;
            OnPropertyChanged("IntType");
        }
    }
}

public String Description
{
    get { return CurrentIntType.Description; }
    set
    {
        if (value != CurrentIntType.Description)
        {
            CurrentIntType.Description = value;
            OnPropertyChanged("Description");
        }
    }
}

【问题讨论】:

    标签: wpf data-binding mvvm datagrid inotifypropertychanged


    【解决方案1】:

    请看我的回答here。它会给你一个可观察的集合,告诉你集合何时发生变化,或者集合中的项目何时发生变化。

    【讨论】:

    • 另外,我在尝试使用 ItemObservableCollection&lt;T&gt; 类时遇到了一个奇怪的错误。我不断收到此编译器错误 CS0311:类型“type1”不能用作泛型类型或方法“”中的类型参数“T”。没有从“type1”到“type2”的隐式引用转换。意思是我的InterestTypeEntity 到System.ComponentModel.INotifyPropertyChanged 没有隐式转换。
    • @myermian:这不是一个奇怪的错误 - 这是通用约束的结果。类型 T 必须实现 INotifyPropertyChanged 才能让 ItemObservableCollection&lt;T&gt; 使用它。因此,您的InterestTypeEntity 必须实现INotifyPropertyChanged。另外,我更新了另一篇文章以包含 ItemPropertyChangedEventArgs 类。
    • 相信我,这很奇怪,因为我将 InterestTypeEntity 作为 AbstractEntity 的子类。 AbstractEntity 实现 INotifyPropertyChanged。事实上,即使我有 InterestTypeEntity 直接实现 INotifyPropertyChanged 它仍然给我那个错误......:-/
    • 我发现这是因为我的实体类型没有实现 INotifyPropertyChanged,而我的 ViewModel 是。这就是我不断收到该错误的原因。
    【解决方案2】:

    不要创建模型对象的集合,也不要在您的(当前)视图模型上实现 IntType 和 Description 属性。除非你有其他理由这样做,否则不要在你的模型中实现属性更改通知。

    相反,将IntTypes 设为InterestTypeEntityViewModel 对象的集合。

    这个类包装了InterestTypeEntity。它公开了IntType 和Description 属性,a) 包装底层InterestTypeEntity 属性和b) 执行属性更改通知。如果你让它的构造函数接受一个InterestTypeEntity 参数,那么很容易在你的视图模型中填充:

    IntTypes = new ObservableCollection<InterestTypeEntityViewModel>(
       DataRepository.InterestTypeEntities.Select(x => new InterestTypeEntityViewModel(x));
    

    将ItemsSource 绑定到此集合。 (另外,将 CurrentIntType 设为 InterestTypeEntityViewModel 类型的属性,并在其更改时引发 PropertyChanged。)

    编辑:

    如果在其集合中的项目的属性发生更改时需要通知拥有视图模型,则使其处理它们引发的PropertyChanged 事件非常简单。在您的构造函数中,添加:

    foreach (InterestTypeEntityViewModel vm in IntTypes)
    {
      vm.PropertyChanged += InterestTypeEntityViewModel_PropertyChanged;
    }
    

    还有这个方法:

    private void InterestTypeEntityViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
       InterestTypeEntityViewModel vm = (InterestTypeEntityViewModel) sender;
       // check e.PropertyName and do whatever you need to do here.
    }
    

    如果你从你的集合中移除一个对象,不要忘记取消注册事件处理程序;否则,子视图模型对象在父视图模型对象完成之前不会被释放。

    请注意,通过这种方式实现视图模型,您可以对底层实体模型的更新进行大量控制。例如,您可以在父视图模型中实现一个命令,该命令在一次操作中完成所有更新,另一个命令允许用户放弃他们在 UI 中所做的所有更改而不执行更新。所有这些逻辑都与实际的表示层很好地解耦了。

    【讨论】:

    • 好吧,我做了必要的更改,我可以让我的 InterestTypeViewModel 接受更改,但是如何冒泡到包含视图模型的 ObservableCollection 的 InterestTypeAllViewModel?
    • 不是全部,但它很简单。查看我的编辑。
    • 以这种方式工作。我真的希望 ItemObservableCollection 能够正常工作,因为这意味着我不必链接其他事件等。但是,必须使用有效的方法。而且,如果我决定创建一个使用 InterestTypeViewModel(不是“All”版本)的视图,它就会派上用场。
    • 让视图模型对象通过事件相互通信是值得的。使用事件确实可以简化很多 UI 问题。
    【解决方案3】:

    总体策略:

    将 TwoWay 添加到您的绑定中:

    SelectedItem="{Binding CurrentIntType,Mode=TwoWay}"
    

    然后在你的 ViewModel 中订阅 observable 集合的 changed 事件。当集合发生变化时,将其发送到您的模型/DAL 并将其持久化。

    【讨论】:

    • 嗯,我看到的唯一问题是我实际上并没有更改集合......相反,我正在更改集合中已经存在的对象的属性。这意味着集合更改的事件永远不会被触发。
    • 根据文档,ObservableCollection changed 事件在“添加、删除、更改、移动或刷新整个列表时触发”。 msdn.microsoft.com/en-us/library/ms653375.aspx
    • 但是item是引用类型,所以引用没有变化。参考中的值正在发生变化。
    • 嗯,有点。 foo[i] = new Foo() 更改 foo 的 ith 元素。 foo[i].Bar = 'x' 没有。
    猜你喜欢
    • 2015-03-11
    • 2012-06-24
    • 2014-01-09
    • 2012-06-12
    • 2013-02-22
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多