Проблема с отображением виртуализации строк DataGrid - PullRequest
26 голосов
/ 30 марта 2012

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

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

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

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

Ответы [ 3 ]

26 голосов
/ 31 марта 2012

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

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

             <tk:DataGrid x:Name="dataGrid" 
             ItemsSource="{Binding Path=Bookings}" 
             AutoGenerateColumns="False" 
             EnableRowVirtualization="True" 
             EnableColumnVirtualization="True"
             VirtualizingStackPanel.VirtualizationMode="Standard"
             VirtualizingStackPanel.IsVirtualizing="True">
4 голосов
/ 31 марта 2012

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

  • отключить виртуализацию
  • давайте предположим / назовем привязку источника элементов вашей таблицы данных как "Rows",

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

Я только что столкнулся с подобной проблемой, и она решена после добавления UpdateSourceTrigger=PropertyChanged к привязке.

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