所以我做了更多的调查,结果发现我的问题是由于 WPF 数据网格的限制。当基础数据发生变化时,它不会自动重新排序集合。换句话说,当您第一次添加项目时,它将被排序并放置在正确的位置,但如果您更改项目的属性,它将不会重新排序。INotifyPropertyChanged 与排序更新无关。它只处理更新显示的数据,但不会触发对其进行排序。强制重新排序的是 CollectionChanged 事件,但修改集合中已经存在的项目不会触发此特定事件,因此不会执行排序。
这是另一个类似的问题:
C# WPF Datagrid does not dynamic sort on data update
该用户的解决方案是手动调用 OnCollectionChanged()。
最后,我结合了这两个线程的答案:
- ObservableCollection 没有注意到其中的项目何时更改(即使使用 INotifyPropertyChanged)
- ObservableCollection 和 Item PropertyChanged
我还添加了“智能”排序,只有在属性更改时才调用 OnCollectionChanged() 是当前在 SortDescription 中使用的值。
public class MessageCollection : ObservableCollection<Message>
{
ICollectionView _view;
public MessageCollection()
{
_view = CollectionViewSource.GetDefaultView(this);
}
public void Sort(string propertyName, ListSortDirection sortDirection)
{
_view.SortDescriptions.Clear();
_view.SortDescriptions.Add(new SortDescription(propertyName, sortDirection));
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
this.AddPropertyChanged(e.NewItems);
break;
case NotifyCollectionChangedAction.Remove:
this.RemovePropertyChanged(e.OldItems);
break;
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
this.RemovePropertyChanged(e.OldItems);
this.AddPropertyChanged(e.NewItems);
break;
}
base.OnCollectionChanged(e);
}
private void AddPropertyChanged(IEnumerable items)
{
if (items != null)
{
foreach (var obj in items.OfType<INotifyPropertyChanged>())
{
obj.PropertyChanged += OnItemPropertyChanged;
}
}
}
private void RemovePropertyChanged(IEnumerable items)
{
if (items != null)
{
foreach (var obj in items.OfType<INotifyPropertyChanged>())
{
obj.PropertyChanged -= OnItemPropertyChanged;
}
}
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
bool sortedPropertyChanged = false;
foreach (SortDescription sortDescription in _view.SortDescriptions)
{
if (sortDescription.PropertyName == e.PropertyName)
sortedPropertyChanged = true;
}
if (sortedPropertyChanged)
{
NotifyCollectionChangedEventArgs arg = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Replace, sender, sender, this.Items.IndexOf((Message)sender));
OnCollectionChanged(arg);
}
}