Проблема с виртуализацией строк в DataGrid

В настоящее время существует DataGrid, связанный с DataTable. Он также имеет столбец шаблона с CheckBox в нем, который мы добавляем программно. Эта цель этого столбца - отслеживание множественных выборов в DataGrid.

A factory используется для создания CheckBox es для каждой строки.

Существует довольно много записей, поэтому для виртуализации строк установлено значение true, чтобы производительность была приемлемой. Однако мы видим странную проблему, если мы проверим некоторые CheckBox es в первых 10 строках, а затем прокрутим вниз примерно на 50 строк (сетка имеет около 10 строк, видимых в любой момент времени), есть куча других CheckBox es, которые, как представляется, проверяются произвольно.

Если отключить виртуализацию строк, эта проблема не существует (но производительность ужасна). Есть ли способ обойти это? Кто-нибудь знает, что мы можем делать неправильно?

Ответ 1

Если вы ищете скорость ListView Gridview намного быстрее (и имеет меньше возможностей).

Попробуйте отключить переработку контейнеров.

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

Ответ 2

Если вы включили виртуализацию, потому что время загрузки datagrid ужасное, то вот решение:

  • отключить виртуализацию
  • позвольте предположить/вызывать привязку источника данных к datagrid как "Строки",

    public IEnumerable<Row> Rows {get; set;}
    
  • Добавьте свойство в свой класс "Row" IsVisible и переключите его, когда вы хотите загрузить данные (а не когда поток пользовательского интерфейса решает разрешить привязку и загружать каждый элемент управления).

причина, по которой это работает, заключается в том, что когда вы загружаете сетку, она проверяет привязку, все строки невидимы, поэтому поток пользовательского интерфейса не должен прокручивать все столбцы строк * для их создания, он может перейти к следующее, что нужно сделать. С другой стороны, вы можете обнаружить, когда удобнее время, чтобы превратить эти строки в видимые, когда View.Visibility видна, когда ViewModel загружает данные откуда-то и т.д. Таким образом, вы находитесь в полном контроле. Ниже я повторяю через источник (строки) элемента, используя задачу (в фоновом потоке), но устанавливая видимость в потоке пользовательского интерфейса.

   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);
        }
    }
  • В представлении, когда загружается datagrid, не разрешайте ему запускать поток пользовательского интерфейса, помещая итерацию строк в фоновый поток, а затем установите для параметра Видимость значение 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 (вы можете проверить доступ, используя что-то еще, вроде anyControl.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>