我正在尝试提高连接到自定义数据对象集合的DataGridView的性能。一旦初始化,集合实际上不会改变大小(即,在启动时加载列表时不添加或删除数据对象),但数据对象的属性会动态更改,并且网格基本上应该是实时显示这些数据对象。
这个实现IBindingListView的集合使用标准的Visual Studio设计器支持数据绑定到DataGridView,从而导致BindingSource在控件和它们的数据源之间扮演代理的正常角色。其他几个控件也使用一些公开的属性(例如,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));
}
}
这对我来说没问题,虽然我们的列表中有几百到几千个数据对象,但我确实注意到网格更新有点迟钝。在测试一些现有功能以批量更新数据时,就会出现死亡(从一个角度来看) - 即,表单上有一个按钮可以翻转 all 数据对象的布尔属性之一在列表中。当此按钮的事件处理程序触发时,它会枚举整个数据对象列表并将标志设置为true / false,并且UI将暂停8-10秒,然后恢复生命并使用更新的布尔值标记所有对象(使用DataGridViewCheckBoxColumn)。
我的第一个想法是在按钮的事件句柄更新所有数据对象时禁用BindingSource的ListChanged事件(RaiseListChangedEvents = false;),但这并没有显着的区别。
我们有一些简单的跟踪,所以我查看了时间戳,日志似乎表明基本上挂起的整个持续时间花费了我在我的数千个左右的数据对象上触发属性更改通知单元测试环境。
如果我在上述批量编辑按钮设置的布尔属性的属性集中注释掉事件通知代码,则挂起完全消失并且网格再次变得活泼 - 但我牺牲了网格更新(即,复选框列单元格不会更新。)
我做了一些搜索,我没有发现很多提到实现INotifyPropertyChanged是我正在处理的对象数量的重要影响因此,所以我不确定我们的代码中是否有错误需要修复 - 例如,我的INotifyPropertyChanged的低效实现,可能是我们的集合类中的IBindingListView的错误实现,或者我们的数据绑定中的一些愚蠢 - 或者如果我在没有实现虚拟模式的情况下达到我在DataGridView中可以做的限制
现在,我已经解开了我编写的INotifyPropertyChanged代码并试图在我认为我们通过使用CellChanged上的事件处理程序,Button Click等对数据对象进行更改时使网格无效......但我可以'帮助我感觉我并不真正理解这里的root perf问题,而且我可能会选择一个不太干净的实现策略,因为我没有得到我的性能问题。
所以我正在寻找关于我的基本方法是否合适的指导/反馈,或者我需要改变实施策略。
TIA, 马特
答案 0 :(得分:1)
在我们当前的应用程序中,有一些大的网格视图,当它们缓慢时,我只需要拍几张照片来看看发生了什么。
一般来说,一直在采取的通知是疯狂的通知。在可能的情况下,最好不要强烈地保持数据与通知一致,而是能够容忍一些暂时的不一致并偶尔在某种一次性通过中清理它。