C#内联排序ObservableCollection不更新数据绑定

时间:2014-12-03 05:04:22

标签: c# sorting mvvm data-binding observablecollection

我有ViewModel,其中包含绑定到ObservableCollection<CustomKeyGroup<CustomItem>>中控件的View属性,问题是我想通过{{1}中的属性对此集合进行排序},而不设置CustomKeyGroup<T>对象属性(即对集合内联排序):

ObservableCollection<...>

从上面的代码中,尝试的内联排序被注释掉(因为它们不会更新数据绑定到它的控件),并且public class MainViewModel : ViewModelBase { ... // data service etc code private ObservableCollection<CustomKeyGroup<CustomItem>> _items = new ObservableCollection<CustomKeyGroup<CustomItem>>(); public ObservableCollection<CustomKeyGroup<CustomItem>> Items { get { return _items; } set { _items = value; RaisePropertyChanged("Items"); } } public void Sort(string _orderBy = null, bool _descending = true) { if (string.IsNullOrEmpty(_orderBy) || this.Items.Count == 0) { return; } var test = this.Items.ToList(); // bubble sort try { for (int i = test.Count - 1; i >= 0; i--) { for (int j = 1; j <= i; j++) { CustomKeyGroup<CustomItem> o1 = test[j - 1]; CustomKeyGroup<CustomItem> o2 = test[j]; bool move = false; var order = typeof(CustomKeyGroup<CustomItem>).GetProperty(orderBy); var t = order.GetValue(o1); var t2 = order.GetValue(o2); // sort comparisons depending on property if (_descending) { // ascending if (t.GetType() == typeof(int)) { // descending and int property if ((int)t < (int)t2) { move = true; } } else { // descending and string property if (t.ToString().CompareTo(t2.ToString()) > 0) { move = true; } } } else { // ascending if (t.GetType() == typeof(int)) { // ascending and int property if ((int)t > (int)t2) { move = true; } } else { // ascending and string property if (t.ToString().CompareTo(t2.ToString()) < 0) { move = true; } } } // swap elements if (move) { //this.Items.Move(j - 1, j); // "inline" test[j] = o1; test[j - 1] = o2; } } } // set property to raise property changed event this.Items = new ObservableCollection<CustomKeyGroup<CustomItem>>(test); } catch (Exception) { Debug.WriteLine("Sorting error"); } //RaisePropertyChanged("Items"); // "inline sort" raise property changed to update Data binding Debug.WriteLine("Sorted complete"); } ... // get data from service, etc. 的手动设置保留(有效,但如果向下滚动)控制和排序,它将带你回到顶部 - 不受欢迎!)。

任何人都知道如何使用内联排序选项更新视图/控件?我还尝试手动提升Items事件(使用MVVMLight ToolkitRaisePropertyChanged中指定)无效。

注意:ObservableObject末尾设置断点显示try-catch 确实已排序,但更改不是反映在ObservableCollection<...>!甚至更奇怪的是,控件(View)的LongListSelector绑定到JumpList的另一个属性,立即成功更新!!如果我点按CustomKeyGroup<T>中的任何一项,JumpList会自动更新,显示已排序的项目......然后我想到设置View DataContext排序后,但这也无法解决问题。

感谢。

1 个答案:

答案 0 :(得分:1)

在这里添加我自己的答案。

因此,根据原始帖子的评论,@ piofusco指出,仅在ObservableCollection已排序时,视图不会更新。即使手动更改集合(因此,提升NotifyPropertyChangedNotifyCollectionChanged)也不会更新它。

再搜索一下,我决定可以使用CollectionViewSource,这将对我进行排序 - 而不更改集合本身(因此允许控件保留其当前滚动位置)。为了使其正常工作,基本上,将新属性添加到ViewModel类型的CollectionViewSource,添加SortDescription,设置其Source并直接绑定到该属性(而不是原ObservableCollection

ViewModel

private CollectionViewSource _sortedCollection = new CollectionViewSource();
public CollectionViewSource SortedCollection {
    get {
        _sortedCollection.Source = this.Items; // Set source to our original ObservableCollection
        return _sortedCollection;
    }
    set {
        if (value != _sortedCollection) {
            _sortedCollection = value;
            RaiseNotifyPropertyChanged("SortedCollection"); // MVVMLight ObservableObject
        }
    }
}

查看XAML(请注意与Property的绑定。查看):

<ListBox ItemsSource="{Binding SortedCollection.View}" ... />

如果你有一个排序按钮,那么在你的View代码隐藏中:

ViewModel _vm = this.DataContext as ViewModel;
viewModel.SortedCollection.SortDescriptions.Clear(); // Clear all 
viewModel.SortedCollection.SortDescriptions.Add(new SortDescription("PropertyName", ListSortDirection.Descending)); // Sort descending by "PropertyName"

繁荣!您的已排序集合应立即在视图中更新!更好的是它保留了ObservableCollection功能,因为对ObservableCollection中对象的任何更新都会引发NotifyPropertyChangedNotifyCollectionChanged处理程序,从而更新视图(同时允许两者)在保留当前滚动位置的同时对对象进行排序和更新)!

注意:对于那些使用LongListSelector控件的用户,我无法让它工作,并且我遇到了更多的互联网挖掘this post,其中讨论了为什么 LLS无法在没有一些修改的情况下绑定到CollectionViewSource.View。所以我最终使用了ListBox控件。您可以阅读一些差异here。但是对于我的任务,ListBox就足够了。