【问题标题】:WPF: Replacing databound collection contents without Clear/AddWPF:在没有清除/添加的情况下替换数据绑定集合内容
【发布时间】:2010-11-29 10:43:50
【问题描述】:

当使用 WPF 数据绑定时,我显然无法按照MyCollection = new CollectionType<Whatever>( WhateverQuery() ); 的方式执行某些操作,因为绑定引用了旧集合。到目前为止,我的解决方法是 MyCollection.Clear();,然后是一个 foreach 做 MyCollection.Add(item); - 这对性能和美观都非常不利。

ICollectionView,虽然很简洁,但也不能解决问题,因为它的SourceCollection 属性是只读的;太可惜了,因为那将是一个不错且简单的解决方案。

其他人是如何处理这个问题的?应该提到的是,我正在做 MVVM,因此无法通过单独的控件绑定进行翻找。我想我可以使用ReplaceSourceCollection() 方法围绕ObservableCollection 进行包装,但在走这条路之前,我想知道是否还有其他最佳实践。

编辑:

对于 WinForms,我会将控件绑定到 BindingSource,允许我简单地更新它的 DataSource 属性并调用 ResetBindings() 方法 - 很快,底层集合有效地改变了。我本来希望 WPF 数据绑定能够开箱即用地支持类似的场景?

示例(伪)代码:WPF 控件(ListBox、DataGrid,无论你喜欢什么)绑定到Users 属性。我意识到集合应该是只读的以避免ReloadUsersBad() 演示的问题,但是这个示例的错误代码显然无法编译:)

public class UserEditorViewModel
{
    public ObservableCollection<UserViewModel> Users { get; set; }

    public IEnumerable<UserViewModel> LoadUsersFromWhateverSource() { /* ... */ }

    public void ReloadUsersBad()
    {
        // bad: the collection is updated, but the WPF control is bound to the old reference.
        Users = new ObservableCollection<User>( LoadUsersFromWhateverSource() );
    }

    public void ReloadUsersWorksButIsInefficient()
    {
        // works: collection object is kept, and items are replaced; inefficient, though.
        Users.Clear();
        foreach(var user in LoadUsersFromWhateverSource())
            Users.Add(user);
    }

    // ...whatever other stuff.
}

【问题讨论】:

  • 你能发一些代码吗?
  • +1 好问题。我已经有一段时间没有在 WPF 中做任何事情了,但是另一种语言的另一个框架有类似的概念,并通过停止运行循环、更改大量属性然后取消暂停运行循环来解决这个问题。我正在寻找类似的东西。

标签: c# wpf data-binding


【解决方案1】:

如果对象MyCollection属于实现INotifyPropertyChanged,您可以简单地替换集合。

一个例子:

public class MyClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private ObservableCollection<Whatever> _myCollection;

    private void NotifyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public ObservableCollection<Whatever> MyCollection
    {
        get
        {
            return _myCollection;
        }
        set
        {
            if (!ReferenceEquals(_myCollection, value))
            {
                _myCollection = value;
                NotifyChanged("MyCollection");
            }
        }
    }
}

有了这个,当你分配一个集合时,WPF 会检测到这个并且一切都会更新。

这就是我要解决的方法。

【讨论】:

  • 当然……我敢肯定我以前也必须这样做。
  • 天啊!它必须简单明了,不是吗? :P
  • 没问题,很高兴能帮上忙。
【解决方案2】:

下面的链接解释了如何实现 AddRange 方法。

http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx

您似乎被困在实现正确处理这种情况的子类上。

显然,某些控件不支持批量集合更改通知。至少在写那篇文章时他们没有。不过,如果您想进一步调查,现在您应该了解更多信息。

【讨论】:

  • 处理批量更新(而不是完全替换)的体面文章 - 讨厌 ListCollectionView 只支持单项更新:|
猜你喜欢
  • 1970-01-01
  • 2011-06-30
  • 2014-06-19
  • 1970-01-01
  • 2014-07-04
  • 1970-01-01
  • 2013-05-13
  • 2013-09-18
相关资源
最近更新 更多