【问题标题】:Should I be having perf issues with a large list of objects implementing INotifyPropertyChanged?我是否应该对大量实现 INotifyPropertyChanged 的​​对象有性能问题?
【发布时间】:2010-07-22 19:07:49
【问题描述】:

我正在尝试提高连接到自定义数据对象集合的 DataGridView 的性能。集合在初始化后实际上并没有改变大小(即,一旦列表在启动时加载,就不会添加或删除数据对象),但是数据对象的属性会动态变化,并且网格基本上应该是实时显示这些数据对象。

这个集合实现了 IBindingListView,使用标准的 Visual Studio 设计器支持将数据绑定到 DataGridView,从而导致 BindingSource 在控件及其数据源之间充当正常的代理角色。一些其他控件也连接到集合类,使用一些公开的摘要属性(例如,TotalCountWithPropertyXXX)

之前,表单上的代码实际上是使用定时器来调用BindingSource.ResetBindings(false);为了更新绑定的控件。我认为这不太理想,所以我在数据对象本身上实现了基本的 INotifyPropertyChanged 支持,以便让对象级道具更改冒泡到 BindingSource 并最终让 DataGridView 自动更新以显示已编辑属性的新值(并且显然取消了对 BindingSource.ResetBindings 的调用)。

我对 INotifyPropertyChanged 的​​实现非常普通:只是从属性访问器的设置器中触发了事件,并使用包含相应属性名称的字符串值,例如:

public event PropertyChangedEventHandler PropertyChanged;

public string Name
{
    get { return _name; }
    set
    {
        if (value != _name)
        {
            _name = value;
            NotifyPropertyChanged("Name");
        }
    }
}

private void NotifyPropertyChanged(String info)
{
    PropertyChangedEventHandler localOnPropChanged = OnPropertyChanged;
    if (localOnPropChanged != null)
    {
        localOnPropChanged(this, new PropertyChangedEventArgs(info));
    }
}

这对我来说没问题,虽然我们的列表中有几百到几千个数据对象,但我确实注意到网格更新有点迟缓。致命一击(从性能的角度来看)是在测试一些现有功能以批量更新数据对象时出现的——即,表单上有一个按钮可以翻转 all 数据对象的布尔属性之一在列表中。当此按钮的事件处理程序触发时,它会枚举整个数据对象列表并将标志设置为 true/false,并且 UI 仅挂起 8-10 秒,然后恢复生命并使用更新的布尔值标记所有对象(使用DataGridViewCheckBoxColumn)。

我的第一个想法是在按钮的事件句柄更新所有数据对象时禁用 BindingSource 的 ListChanged 事件触发 (RaiseListChangedEvents = false;),但这并没有明显的区别。

我们有一些简单的跟踪,所以我查看了时间戳,日志似乎显示基本上整个挂起持续时间都用于触发我在我拥有的大约一千个数据对象上的属性更改通知单元测试环境。

如果我在属性集中为由上述批量编辑按钮设置的布尔属性注释掉事件通知代码,挂起完全消失,网格再次变得活泼——但我牺牲了网格更新(即,复选框列单元格不会更新。)

我进行了一些搜索,但没有发现太多关于实现 INotifyPropertyChanged 对我正在处理的对象数量的重大影响,所以我不确定我们的代码中是否有错误需要被修复——例如,我对 INotifyPropertyChanged 的​​低效实现,可能是我们的集合类中 IBindingListView 的错误实现,或者我们的数据绑定中的一些愚蠢的东西——或者如果我在没有实现虚拟模式的情况下达到了我在 DataGridView 中可以做的限制.

现在,我已经取消了我编写的 INotifyPropertyChanged 代码,并尝试在我认为我们通过使用 CellChanged、Button Click 等事件处理程序对数据对象进行更改时使网格无效......但我可以'感觉我并不真正理解这里的根本性能问题,并且我可能选择了一个不太干净的实施策略,只是因为我不明白我的性能问题到底是什么。

因此,我正在寻找一些指导/反馈,以了解我的基本方法是否可行,或者我需要更改实施策略。

TIA, 马特

【问题讨论】:

  • 您确实应该将编程语言添加到标签中。使用这些标签,您不会受到任何关注。

标签: c# performance datagridview .net-2.0 inotifypropertychanged


【解决方案1】:

在我们当前的应用中,有一些大的网格视图,当它们运行缓慢时,我只需拍几张堆栈照片看看发生了什么。

通常情况下,通知变得疯狂。在可能的情况下,最好不要试图强烈地保持数据与通知的一致性,而是能够容忍一些暂时的不一致,并偶尔通过某种一次性传递来清理它。

【讨论】:

  • 谢谢迈克。很高兴知道通知的激增是一个真正的原因。拍摄堆栈照片的最佳方式是什么?
  • 不确定您是打算使用分析工具还是只是暂停调试器并查看线程的调用堆栈,但我做了后者并设法获得了足够的通知和昂贵的操作,我现在已经有了可以接受的表现。谢谢!
猜你喜欢
  • 2019-01-17
  • 1970-01-01
  • 1970-01-01
  • 2016-06-13
  • 2015-09-16
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多