DataGrid行虚拟化显示问题

时间:2012-03-30 19:33:33

标签: wpf datagrid row virtualization

我们目前有DataGrid绑定到DataTable。它还有一个模板列,其中包含CheckBox,我们以编程方式添加它。此列的目的是跟踪DataGrid中的多个选择。

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

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

如果我们禁用行虚拟化,则此问题不存在(但性能非常糟糕)。有没有办法解决?谁知道我们可能做错了什么?

3 个答案:

答案 0 :(得分:25)

如果您正在寻找速度ListView Gridview要快得多(并且功能较少)。

尝试禁用容器回收。

             <tk:DataGrid x:Name="dataGrid" 
             ItemsSource="{Binding Path=Bookings}" 
             AutoGenerateColumns="False" 
             EnableRowVirtualization="True" 
             EnableColumnVirtualization="True"
             VirtualizingStackPanel.VirtualizationMode="Standard"
             VirtualizingStackPanel.IsVirtualizing="True">

答案 1 :(得分:4)

如果您打开虚拟化因为数据网格加载时间很糟糕,那么,这是解决方案:

  • 关闭虚拟化
  • 让我们假设/将您的datagrid项目源绑定称为“Rows”,

    public IEnumerable<Row> Rows {get; set;}
    
  • 在“Row”类IsVisible中添加一个属性,并在想要加载数据时切换它(不是在UI线程决定解析绑定并加载每个控件时)

这个工作的原因,是因为当你加载网格时,它检查绑定,所有行都是不可见的,所以UI线程不必旋转你所有的行*列来创建它们,它可以去接下来需要做的事情。另一方面,您可以检测何时是方便的时间将这些行转换为可见,当View.Visibility可见时,ViewModel从某处加载数据等等。因此您完全可以控制。下面我使用任务(在后台线程中)迭代我的项目源(行),但在UI线程上设置可见性。

   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线程,然后将“可见性”设置为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);
    }
    

答案 2 :(得分:1)

我遇到了类似的问题,并在将UpdateSourceTrigger=PropertyChanged添加到绑定后解决了问题。

<DataGridTemplateColumn Header="Visible">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding IsShown,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>