DataGrid行虚拟化显示问题



我们当前有一个绑定到DataTableDataGrid。它还有一个模板列,其中有一个CheckBox,我们用程序添加它。此列的目的是跟踪DataGrid中的多项选择。

工厂用于为每一行创建CheckBox es。

有相当多的记录,所以行虚拟化设置为true,这样性能就可以接受了。然而,我们看到了一个奇怪的问题,如果我们在前10行检查一些CheckBoxes,然后向下滚动大约50行(网格在任何时候都有大约10行可见),那么还有一堆其他CheckBoxes似乎是随机检查的。

如果我们禁用行虚拟化,这个问题就不存在(但性能很糟糕)。有办法解决这个问题吗?有人知道我们可能做错了什么吗?

如果你正在寻找速度,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>

最新更新