我正在尝试提高连接到自定义数据对象集合的DataGridView的性能。一旦初始化,集合实际上不会改变大小(即,一旦启动时加载列表,就不会添加或删除任何数据对象),但是数据对象的属性会动态改变,网格基本上应该是这些数据对象的实时显示。
这个实现IBindingListView的集合使用标准的visualstudio设计器支持将数据绑定到DataGridView,从而在控件和它们的数据源之间产生一个具有代理角色的BindingSource。一些其他控件也连接到collection类,使用一些公开的摘要属性(例如TotalCountWithPropertyXXX)
以前,表单上的代码实际上使用计时器调用BindingSource.ResetBindings(false);以更新绑定控件。我觉得这不太理想,因此,我在数据对象本身上实现了基本的INotifyPropertyChanged支持,以便将对象级的属性更改冒泡到BindingSource,并最终使DataGridView自动更新自身以显示已编辑属性的新值(显然取消了对BindingSource.ResetBindings的调用)。
我的INotifyPropertyChanged实现非常简单:只是用包含相应属性名的字符串值从属性访问器的setter触发了事件,例如:
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));
}
}
这对我来说还行,尽管我们的列表中有几百到几千个数据对象,但我确实注意到网格更新有点迟缓。致命一击(从perf的角度)是在测试一些现有的功能来批量更新数据对象时出现的,也就是说,表单上有一个按钮可以翻转其中一个布尔属性
全部的
列表中的数据对象。当此按钮的事件处理程序启动时,它会枚举整个数据对象列表,并将标志设置为true/false,UI仅挂起8-10秒,然后恢复正常并使用更新的布尔值标记所有对象(使用DataGridViewCheckBoxColumn)。
我们有一些简单的跟踪,所以我查看了时间戳,日志似乎显示挂起的整个持续时间基本上都花在对我在单元测试环境中的大约1000个数据对象触发属性更改通知上。
我做了一些搜索,我没有发现太多关于实现INotifyPropertyChanged的内容,这对于我处理的对象数量来说是一个显著的性能影响,所以我不确定我们的代码中是否有需要修复的bug——例如,我对INotifyPropertyChanged的低效实现,也许在我们的集合类中IBindingListView的实现不好,或者在我们的数据绑定中有什么愚蠢的东西——或者如果我在DataGridView中没有实现虚拟模式就达到了极限。
目前,我已经解开了我编写的INotifyPropertyChanged代码,并尝试在我认为数据对象发生更改时通过使用CellChanged上的事件处理程序、按钮单击等使网格无效。。。但是我忍不住觉得我不太理解这里的根性能问题,我可能会选择一个不太干净的实现策略,因为我不明白我的性能问题到底是什么。
蒂亚,
马特