2014-12-03 90 views
1

我有一个ViewModel其中包含ObservableCollection<CustomKeyGroup<CustomItem>>属性绑定到一个View控制,问题是,我想这个集合的一个属性CustomKeyGroup<T>进行排序,而无需设置ObservableCollection<...>对象属性(即分类收集在线):C#内嵌排序的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. 

从上面的代码中,试图内嵌各种被注释掉了(因为它们不更新databinds它的控制),以及Items手动设置留(工作,但如果您向下滚动控件并进行排序,它会将您带回顶部 - 不受欢迎!)。

任何人都有任何想法如何使用内联排序选项更新视图/控件?我也尝试手动提高RaisePropertyChanged事件(在ObservableObject中指定使用MVVMLight Toolkit)无济于事。

注:try-catch结束设置断点揭示了ObservableCollection<...>确实排序,但更改只是不会在View体现!即使更蹊跷的是,控制(LongListSelector)有一个JumpList绑定到CustomKeyGroup<T>的另一个属性它成功立即更新!如果我点击JumpList中的任何项目,View正确更新自身,揭示排序项目...然后,我想在排序后设置ViewDataContext,但这也不能解决问题。

谢谢。

+0

对WPF中的集合排序可能会有问题。看到这里:http://stackoverflow.com/questions/1945461/how-do-i-sort-an-observable-collection?rq=1 – piofusco 2014-12-08 17:47:52

+0

感谢您的答复。我认为我的问题通常与WP/Silverlight有关,因为我能够完美地对ObservableCollection进行排序,问题出现在XAML绑定中。它(控件,在这种情况下是LLS)在集合排序之后不会更新(在排序后检查集合时使用断点显示它已被排序)。 – 2014-12-08 23:16:20

+0

你击中了头部。除非您将ObservableCollection设置为新排序的ObservableCollection,否则这些更改将不会被标记,因此您的视图将不会更新。 – piofusco 2014-12-08 23:43:23

回答

0

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

因此,根据原始帖子的评论,@piofusco指出,当仅对ObservableCollection进行排序时,View不会更新。即使手动更改集合(因此,提高NotifyPropertyChangedNotifyCollectionChanged)也不会更新它。

多搜索一下,我决定我可以利用CollectionViewSource,它可以为我排序,而无需更改集合本身(因此允许控件保留当前的滚动位置)。为了得到它的工作,基本上,添加一个新的属性CollectionViewSource类型的ViewModel,添加一个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(注意结合物业查看):

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

而且在你r查看代码隐藏,如果你有一个分类按钮:

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就足够了。