在可观察集合顺序 - C# UWP 中添加项
本文关键字:UWP 添加 观察 集合 顺序 | 更新日期: 2024-10-30 21:45:55
我有一个问题,这很无聊,我花了很多时间用最好的方式解决我的问题。
问题:我有两个可观察集合。(OCAux - Auxiliar OC, OCMain - Main OC Binded UI)
我有请求 http,5 个请求。 对于请求的每个响应,都会添加到项目中 OCAux,然后对项目进行排序。将其添加到订购到我的OCMain的每个项目中后,这会自动通知UI(绑定)。问题是,在添加新项目时,这不是订购的,因为我的订单是OCAux的结果,即仅根据请求请求订单。如果您在将项目添加到 OCMain 后订购项目,它确实会闪烁。我可以在每次添加项目时订购 OCMain,但在添加项目时会导致 UI 闪烁。
这被规避如下,但 UI 中仍然存在这些"闪烁":
foreach (var item in OCMain)
{
OCAux.Add(item);
}
ObservableCollection<Movies> moviesSortedByDatetime= new ObservableCollection<Movies>
(OCAux.OrderByDescending(item=> item.DateTime));
OCMain.Clear();
foreach (var item in moviesSortedByDatetime)
{
if (!OCMain.Contains(item))
{
OCMain.Add(item);
}
}
有人知道如何将插入项放在可观察集合的正确位置吗?
提前致谢
对于批量插入,对于每个更改不断更新 UI 可能是(除非您需要实时更新)。除非您有充分的理由保留OCAux
否则我会OCMain
具有自定义IObservableCollection
实现的有序集合,以在批处理完成后推迟通知。可以通过两种方式完成:
1)最简单的方法是添加一个禁用通知的BeginUpdate()
方法。完成集合作业后,使用 EndUpdate()
重新启用通知。从ObservableCollection<T>
继承的类的概念证明:
public void BeginUpdate() {
_disableNotifications = true;
}
public void EndUpdate() {
_disableNotifications = false;
if (_changed) {
OnCollectionChanged(
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
_changed = false;
}
}
protected override OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
if (_disableNotifications)
_changed = true;
else
base.OnCollectionChanged(e);
}
只需将相同的逻辑也应用于INotifyPropertyChanged
Count
和Items
属性的接口引发事件PropertyChanged
。
2)第二个选项有点复杂,但即使您不知道批量操作何时开始和结束,它也可以工作。首先,让我们做一个假设:如果更新延迟 100 毫秒,用户不会注意到。在这种情况下,我们可以做的是忽略更改并在 NotificationDelay
毫秒后仅发送一个NotifyCollectionChangedAction.Reset
。无论您有多少更新,只需在第一个更新的 NotificationDelay
毫秒后发送一个更新。概念验证:
protected override OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
// Another event already queued a delayed notification
if (_isTimerRunning)
return;
// Assuming _timer is a System.Timers.Timer object already configured
// and OnTimerElapsed method attached to its Elapsed event. Note that
// you may also use System.Threading.Timer, pick the proper one
// according to MSDN and your requirements
_isTimerRunning = true;
_timer.Start();
}
private void OnTimerElapsed(Object source, ElapsedEventArgs e) {
_isTimerRunning = false;
_timer.Stop();
base.OnCollectionChanged(
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
同样,您必须为INotifyPropertyChanged
实现做类似的事情。
请注意,在这两种情况下,我们都会删除一些信息,因为CollectionChanged
不会触发,例如,使用 NotifyCollectionChangedAction.Add
但仅使用 NotifyCollectionChangedAction.Reset
。无论如何,如果只是为了绑定,那么您对INotifyPropertyChanged
通知更感兴趣,这应该不是问题。