摘要定製的ObservableCollection <T>或的BindingList <T>具有用於定期通知
支撐我有一個大的迅速變化的數據集,其我想結合的UI(用數據網格分組)。這些變化分兩個層次。
- 物品經常添加或刪除從集合(500第二每一路)
- 每一個項目都有一個4個屬性,這將向上在其一生中更改爲5倍
的特性數據如下;
- 有收集
- 可以內的第二,被添加的項目在〜5000項然後有5條屬性的修改,然後被去除。
- 的項目也可以保留在一些中間狀態的同時,應顯示給用戶。
這我有問題關鍵的要求;
- 用戶應該能夠通過任何財產數據集進行排序的對象
我想什麼做什麼;
- 更新UI僅每Ñ秒
- 擡起只有相關NotifyPropertyChangedEvents
如果第1項具有屬性State其從A 移動 - >乙 - 「ç - > d在 間隔,我需要/想提高只有一個「國家」的變化 事件,A-> d。
我很欣賞用戶不需要每秒更新數千次UI。如果添加了一個項目,其狀態已更改,並且在UI更新之間N秒的窗口內全部刪除,它不應該擊中DataGrid。
數據網格
數據網格是我使用來顯示數據的組件。我目前使用XCeed DataGrid,因爲它提供了動態分組。我沒有情緒上的投資,如果我可以提供一些動態分組選項(其中包括頻繁更改的屬性),股票DataGrid會很好。
在我的系統的瓶頸是 目前採取的重新排序 的時間,當一個項目的性質發生變化
這需要CPU的98%,在YourKit探查。
一種不同的方式表達出該問題
給定兩個的BindingList /的ObservableCollection其最初相同的情況下 但 第一清單從那以後有一系列 額外的更新(您可以 聽for),生成最小集合 的變更,將其中一個列表變成 其他。
外部讀取
我需要的是由喬治·Tryfonas的這個ArrayMonitor的等價的,但推廣到支持添加和項目的去除(他們將永遠不會被移動)。
注意:如果能想到更好的總結,我會很感激有人編輯問題的標題。
編輯 - 我的解決辦法
的XCeed網格結合細胞直接而排序&分組功能是通過在升高的BindingList的ListChangedEvents從動在網格中的項目。這有點違反直觀性,並排除了下面的MontioredBindingList,因爲行將在組之前更新。
取而代之,我自己包裝物品,捕捉Property改變的事件並按照Daniel的建議將它們存儲在HashSet中。這適用於我,我週期性地迭代這些項目並要求他們通知任何更改。
MonitoredBindingList.cs
這是我在這可以輪詢更新通知的綁定列表嘗試。有可能有一些錯誤,因爲它最終對我毫無用處。
它創建一個添加/刪除事件隊列並通過列表跟蹤更改。 ChangeList與底層列表的順序相同,以便在我們通知添加/刪除操作後,您可以針對正確的索引提出更改。
/// <summary>
/// A binding list which allows change events to be polled rather than pushed.
/// </summary>
[Serializable]
public class MonitoredBindingList<T> : BindingList<T>
{
private readonly object publishingLock = new object();
private readonly Queue<ListChangedEventArgs> addRemoveQueue;
private readonly LinkedList<HashSet<PropertyDescriptor>> changeList;
private readonly Dictionary<int, LinkedListNode<HashSet<PropertyDescriptor>>> changeListDict;
public MonitoredBindingList()
{
this.addRemoveQueue = new Queue<ListChangedEventArgs>();
this.changeList = new LinkedList<HashSet<PropertyDescriptor>>();
this.changeListDict = new Dictionary<int, LinkedListNode<HashSet<PropertyDescriptor>>>();
}
protected override void OnListChanged(ListChangedEventArgs e)
{
lock (publishingLock)
{
switch (e.ListChangedType)
{
case ListChangedType.ItemAdded:
if (e.NewIndex != Count - 1)
throw new ApplicationException("Items may only be added to the end of the list");
// Queue this event for notification
addRemoveQueue.Enqueue(e);
// Add an empty change node for the new entry
changeListDict[e.NewIndex] = changeList.AddLast(new HashSet<PropertyDescriptor>());
break;
case ListChangedType.ItemDeleted:
addRemoveQueue.Enqueue(e);
// Remove all changes for this item
changeList.Remove(changeListDict[e.NewIndex]);
for (int i = e.NewIndex; i < Count; i++)
{
changeListDict[i] = changeListDict[i + 1];
}
if (Count > 0)
changeListDict.Remove(Count);
break;
case ListChangedType.ItemChanged:
changeListDict[e.NewIndex].Value.Add(e.PropertyDescriptor);
break;
default:
base.OnListChanged(e);
break;
}
}
}
public void PublishChanges()
{
lock (publishingLock)
Publish();
}
internal void Publish()
{
while(addRemoveQueue.Count != 0)
{
base.OnListChanged(addRemoveQueue.Dequeue());
}
// The order of the entries in the changeList matches that of the items in 'this'
int i = 0;
foreach (var changesForItem in changeList)
{
foreach (var pd in changesForItem)
{
var lc = new ListChangedEventArgs(ListChangedType.ItemChanged, i, pd);
base.OnListChanged(lc);
}
i++;
}
}
}
喜丹尼爾 - 感謝這樣一個快速和深入的響應。儘管你糾正了我正在犯的一些錯誤,但我一直試圖完全實現你所描述的內容。當我完成課程後,我會將其發佈回來,以便任何人都可以使用或改編它。我還有一個額外的問題,在我的CustomObservableCollection中,當項目發生更改時應該引發什麼事件?或者我該如何傳播'INotifyPropertyChanged'到數據網格? 'NotifyCollectionChangedAction.Replace'似乎不正確。 – CityView 2011-03-15 11:26:15
@CityView:它不是集合的任務通知有關改變其項目性質的數據網格。當你收集綁定到DataGrid,將DataGrid綁定到您的收藏的CollectionChanged事件,並顯示每一個項目的PropertyChanged事件。 – 2011-03-15 11:32:40
@Daniel:有道理 - [XCeed Grid]不是這種情況(http://xceed.com/CS/blogs/dontpanic/archive/2009/04/01/i-notify-we-notify-we -all-wait-no-we-don-t.aspx)這就是爲什麼我感到困惑。 Exceed你需要擴展BindingList。謝謝,我今天會發布我的嘗試。 – CityView 2011-03-15 11:44:40