在DataGrid的应用中,有一种场景是需要保持DataGrid上的多选项,然而在执行了View.Refresh方法后,DataGrid的选中项将不会保持,因此需要后台设置DataGrid的多选项,DataGrid提供的接口只能通过DataGrid.SelectedItems.Add方法一条一条添加选中项,这种方法在需要设置选中项数据少的情况下不会有明显的性能问题,但当后台需要选中的数据量较多时,性能问题很严重。这里通过一个例子说明。
private void DataGridSelectedAllOne(System.Windows.Controls.DataGrid dt) { if (null == dt) return; foreach (var item in dt.Items) { dt.SelectedItems.Add(item); } }
上面是一个简单的例子执行DataGrid当前所有项选中。实际测试中,每一项数据是一个简单的类,包含两个属性,随机产生10000条数据,执行上面的代码耗费的时间在20s左右,这在实际应用中是难以接受到。
通过查看DataGrid的源码,了解到,每一次Add操作都会刷新UI,相当耗时,幸运的是,源码了提供了刷新选中项开始及结束的方法,分别为BeginUpdateSelectedItems和EndUpdateSelectedItems,前一个方法执行后,对SelectedItems进行的操作不会刷新UI,直到后一个方法执行才会一次提交更改,刷新UI,满足要求。参考源码中删除选中项的事例完美的解决了性能问题。代码如下:
private void DataGridSelectedAllTwo(System.Windows.Controls.DataGrid dt) { if (null == dt) return; var type = typeof (MultiSelector); var isUpdatingSelectedItemsProperty = type.GetProperty("IsUpdatingSelectedItems", BindingFlags.Instance | BindingFlags.NonPublic); var beginUpdateFuncProperty = type.GetMethod("BeginUpdateSelectedItems", BindingFlags.Instance | BindingFlags.NonPublic); var endUpdateFuncProperty = type.GetMethod("EndUpdateSelectedItems", BindingFlags.Instance | BindingFlags.NonPublic); var updatingSelectedItems = (bool) isUpdatingSelectedItemsProperty.GetValue(dt); if (!updatingSelectedItems) { beginUpdateFuncProperty.Invoke(dt, null); } try { foreach (var item in dt.Items) { dt.SelectedItems.Add(item); } } finally { if (!updatingSelectedItems) { endUpdateFuncProperty.Invoke(dt, null); } } }
用上面代码执行10000条数据全选操作只需要19ms,20s对19ms,这性能提高不言而喻!