我有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 Toolkit在RaisePropertyChanged
中指定)无效。
注意:在ObservableObject
末尾设置断点显示try-catch
确实已排序,但更改不是反映在ObservableCollection<...>
!甚至更奇怪的是,控件(View
)的LongListSelector
绑定到JumpList
的另一个属性,它立即成功更新!!如果我点按CustomKeyGroup<T>
中的任何一项,JumpList
会自动更新,显示已排序的项目......然后我想到设置View
DataContext
排序后,但这也无法解决问题。
感谢。
答案 0 :(得分:1)
在这里添加我自己的答案。
因此,根据原始帖子的评论,@ piofusco指出,仅在ObservableCollection
已排序时,视图不会更新。即使手动更改集合(因此,提升NotifyPropertyChanged
或NotifyCollectionChanged
)也不会更新它。
再搜索一下,我决定可以使用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
中对象的任何更新都会引发NotifyPropertyChanged
或NotifyCollectionChanged
处理程序,从而更新视图(同时允许两者)在保留当前滚动位置的同时对对象进行排序和更新)!
注意:对于那些使用LongListSelector
控件的用户,我无法让它工作,并且我遇到了更多的互联网挖掘this post,其中讨论了为什么 LLS无法在没有一些修改的情况下绑定到CollectionViewSource.View
。所以我最终使用了ListBox
控件。您可以阅读一些差异here。但是对于我的任务,ListBox
就足够了。