【问题标题】:DataGrid row virtualization display issueDataGrid 行虚拟化显示问题
【发布时间】:2012-04-14 12:22:14
【问题描述】:

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

工厂用于为每一行创建CheckBoxes。

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

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

【问题讨论】:

  • 当您说移除虚拟化后性能很糟糕时,是加载还是滚动时很糟糕。如果它正在加载,有一个解决方案可以让它不那么糟糕,滚动是另一个问题......
  • 它仅在加载时。所有的性能损失都在包含 DataGrid 的窗口的 Show 方法上。使用行虚拟化,在 DataGrid 中显示 2,500 条记录需要 200 毫秒。如果没有行虚拟化,则需要 28 秒。
  • 为你添加了一些代码...几天前刚刚在工作中调整了性能,就像一个魅力

标签: wpf datagrid row virtualization


【解决方案1】:

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

尝试禁用容器回收。

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

【讨论】:

  • 如果您在 VirtualisationMode 之前编写 IsVirtualising,则会出现异常(至少在 .NET 4.5 中)...您需要更改顺序
  • 我遇到了类似的问题,除了滚动时行的顺序不断变化。我没有明确地进行虚拟化。尽管如此,这个答案还是有帮助的。
  • VirtualizationMode="Standard" 致胜!
【解决方案2】:

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

  • 关闭虚拟化
  • 让我们假设/调用您的数据网格的项目源绑定为“行”,

    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 线程,然后将 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);
    }
    

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-02
      • 1970-01-01
      • 2017-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多