我们当前有一个绑定到DataTable
的DataGrid
。它还有一个模板列,其中有一个CheckBox
,我们用程序添加它。此列的目的是跟踪DataGrid
中的多项选择。
工厂用于为每一行创建CheckBox
es。
有相当多的记录,所以行虚拟化设置为true,这样性能就可以接受了。然而,我们看到了一个奇怪的问题,如果我们在前10行检查一些CheckBox
es,然后向下滚动大约50行(网格在任何时候都有大约10行可见),那么还有一堆其他CheckBox
es似乎是随机检查的。
如果我们禁用行虚拟化,这个问题就不存在(但性能很糟糕)。有办法解决这个问题吗?有人知道我们可能做错了什么吗?
如果你正在寻找速度,ListView Gridview要快得多(而且功能更少)。
尝试禁用容器回收。
<tk:DataGrid x:Name="dataGrid"
ItemsSource="{Binding Path=Bookings}"
AutoGenerateColumns="False"
EnableRowVirtualization="True"
EnableColumnVirtualization="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
VirtualizingStackPanel.IsVirtualizing="True">
如果您打开虚拟化是因为数据网格加载时间太长,那么,以下是解决方案:
- 关闭虚拟化
-
让我们假设/调用数据网格的项目源绑定为"行",
public IEnumerable<Row> Rows {get; set;}
-
在"Row"类IsVisible中添加一个属性,并在您想要加载数据时切换它(而不是在UI线程决定解析绑定并加载每个控件时)
这之所以有效,是因为当你加载网格时,它会检查绑定,所有的行都是不可见的,所以UI线程不必旋转所有的行*列来创建它们,它可以进行下一步需要做的事情。另一方面,你可以检测何时方便地将这些行变成可见行,何时View.Visibility可见,当ViewModel从某个地方加载数据时,等等。所以你完全可以控制。下面,我使用一个任务(在后台线程中)迭代我的项目源(行),同时在UI线程上设置Visibility。
private _isVisible = false;
/// <summary>
/// is false by default, for performance when loading first time.
/// </summary>
public bool IsVisible
{
get { return _isVisible; }
set
{
if (_isVisible == value)
return;
_isVisible = value;
RaisePropertyChanged(() => IsVisible);
}
}
在视图中,当数据网格加载时,不允许它通过将行的迭代放在后台线程中来占用UI线程,然后将Visibility设置为true。即使您在后台线程上,更改的IsVisible属性也会触发您进行更新。
private void OnGridLoaded(object sender, RoutedEventArgs e) { //sample bool checks, you might not need them... if (firstTimeLoad && !_isDataGridLoaded) { Task.Factory .StartNew(() => { /*first time loading performance tweak*/ foreach (var row in _viewModel.Rows) ExeOnUi(() => { row.IsVisible = true; }); _firstTimeLoad = false; }) }
忘记添加ExeOnUi代码(你可能会使用whateverControl.Dispatcher.CheckAccess之类的其他东西检查访问,我只使用Microsoft.Practices.ServiceLocator):
static void ExeOnUi (Action action) { var srv= ServiceLocator.Current.GetInstance<IDispatchService> (); if (srv.CheckAccess ()) action.Invoke (); else srv.Invoke (action); }
我刚刚遇到了类似的问题,在将UpdateSourceTrigger=PropertyChanged
添加到绑定后解决了这个问题。
<DataGridTemplateColumn Header="Visible">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsShown,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>