Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 自定义可观察采集<;T>;或绑定列表<;T>;支持定期通知_C#_Wpf_Observablecollection_Large Data Volumes_Bindinglist - Fatal编程技术网

C# 自定义可观察采集<;T>;或绑定列表<;T>;支持定期通知

C# 自定义可观察采集<;T>;或绑定列表<;T>;支持定期通知,c#,wpf,observablecollection,large-data-volumes,bindinglist,C#,Wpf,Observablecollection,Large Data Volumes,Bindinglist,摘要 我有一个快速变化的数据集,我希望将其绑定到UI(带有分组的Datagrid)。变化分为两个层次 经常从集合中添加或删除项目(每种方式每秒500个) 每个项目有4个属性,在其生命周期内最多可更改5次 数据的特点如下: 藏品中约有5000件 一个项目可以在一秒钟内添加,然后进行5次属性更改,然后删除 项目也可能会在某个临时状态下保留一段时间,并应向用户显示 我遇到问题的关键需求 用户应该能够根据对象上的任何属性对数据集进行排序 我想做什么 仅每N秒更新一次UI 仅引发相关Noti

摘要

我有一个快速变化的数据集,我希望将其绑定到UI(带有分组的Datagrid)。变化分为两个层次

  • 经常从集合中添加或删除项目(每种方式每秒500个)
  • 每个项目有4个属性,在其生命周期内最多可更改5次
数据的特点如下:

  • 藏品中约有5000件
  • 一个项目可以在一秒钟内添加,然后进行5次属性更改,然后删除
  • 项目也可能会在某个临时状态下保留一段时间,并应向用户显示
我遇到问题的关键需求

  • 用户应该能够根据对象上的任何属性对数据集进行排序
我想做什么

  • 仅每N秒更新一次UI
  • 仅引发相关NotifyPropertyChangedEvents
如果项目1的属性状态为 从中的A->B->C->D移动 间隔我只需要/想要一个“状态”更改 要引发的事件,A->D

我很感激用户不需要每秒更新数千次UI。如果在UI更新之间的N秒时间内添加、更改和删除了某个项,则该项永远不会访问DataGrid

数据网格

DataGrid是我用来显示数据的组件。我目前正在使用XCeed DataGrid,因为它提供了简单的动态分组。我没有感情上的投入,如果我能提供一些动态分组选项(包括频繁变化的属性),股票数据网格就可以了

我的系统中的瓶颈是 当前在重新排序所需的时间内 当项目的属性更改时

这占用了YourKit探查器98%的CPU

用不同的方式表达问题

给定两个BindingList/ObservableCollection实例 最初是相同的,但是 第一份名单已经有了一系列的问题 其他更新(您可以 侦听),生成最小集 将一个列表转换为 其他的

外部阅读

我需要的是George Tryfonas的一个等价物,但它被推广到支持添加和删除项目(它们永远不会被移动)

注意:如果有人能想出一个更好的摘要,我将非常感谢他们编辑问题的标题

编辑-我的解决方案

XCeed网格将单元格直接绑定到网格中的项目,而排序和分组功能则由BindingList上提出的ListChangedEvents驱动。这有点违反直觉,排除了下面的MontioredBindingList,因为行将在组之前更新

相反,我将项目本身包装起来,捕获属性更改的事件,并按照Daniel的建议将它们存储在哈希集中。这对我来说很有效,我定期迭代这些项目,并要求他们通知任何更改

MonitoredBindingList.cs

下面是我尝试创建的绑定列表,它可以轮询更新通知。它可能有一些bug,因为它最终对我没有用处

它创建一个添加/删除事件队列,并通过列表跟踪更改。变更列表与基础列表的顺序相同,因此在我们通知添加/删除操作后,您可以根据正确的索引进行更改

/// <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++;
        }
    }
}
//
///允许轮询而不是推送更改事件的绑定列表。
/// 
[可序列化]
公共类MonitoredBindingList:BindingList
{
私有只读对象publishingLock=新对象();
专用只读队列addRemoveQueue;
私有只读链接列表变更列表;
私有只读词典changeListDict;
公共监视绑定列表()
{
this.addRemoveQueue=新队列();
this.changeList=新建LinkedList();
this.changeListDict=新字典();
}
受保护的重写void OnListChanged(ListChangedEventArgs e)
{
锁(发布锁)
{
开关(如ListChangedType)
{
案例列表ChangedType.ItemAdded:
如果(e.NewIndex!=计数-1)
抛出新的ApplicationException(“项目只能添加到列表的末尾”);
//将此事件排队等待通知
addRemoveQueue.Enqueue(e);
//为新条目添加空的更改节点
changeListDict[e.NewIndex]=changeList.AddLast(newhashset());
打破
案例列表ChangedType.ItemDeleted:
addRemoveQueue.Enqueue(e);
//删除此项目的所有更改
changeList.Remove(changeListDict[e.NewIndex]);
for(int i=e.NewIndex;i0)
changeListDict.Remove(计数);
打破
案例ListChangedType.ItemChanged:
changeListDict[e.NewIndex].Value.Add(e.PropertyDescriptor);
打破
违约:
基数.唯一值(e);
打破
}
}
}
公共无效发布更改()
{
锁(发布锁)
发布();
}
内部作废发布()
{
while(addRemoveQueue.Count!=0)
{
base.OnListChanged(addRemoveQueue.Dequeue());
}
//变更列表中条目的顺序与'