Проблемы производительности при перемещении/скрытии столбцов в большом wpf datagrid

Я использую wpf datagrid для отображения большого количества данных (около 100 столбцов и 1000 строк). Столбцы привязаны к свойствам, динамически добавляемым с помощью typedescripter. По умолчанию в datagrid отображаются все столбцы, однако мы добавили функциональность, которая позволяет пользователю видеть только подмножество всех столбцов, а также изменять порядок отображения столбцов. В настоящее время я добиваюсь этого, переключая свойство видимости столбцов и изменяя их displayindex. Однако производительность при этом очень низкая.

Ниже приведен пример для воспроизведения проблемы

XAML выглядит довольно просто

<Window x:Class="WpfDataGridTestApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    WindowState="Maximized">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0" Height="Auto" Margin="5">
        <CheckBox x:Name="ApplyColumns" Width="200" Margin="5" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked">Show Predefined Columns</CheckBox>
    </StackPanel>
    <DataGrid 
        x:Name="Grid" EnableColumnVirtualization="False"
         EnableRowVirtualization="False"
        Grid.Row="1" SelectionUnit="Cell"
        ItemsSource="{Binding MyDataView}">
    </DataGrid>
</Grid>

Код выглядит следующим образом

    public partial class MainWindow : Window
{
    /// <summary>
    /// this dictionary stores the column name of columns to display and their displayIndex
    /// </summary>
    Dictionary<string,int> _predefinedColumns=new Dictionary<string, int>()
                                                  {
                                                      {"Column_8",0},
                                                      {"Column_9",1},
                                                      {"Column_11",2},
                                                      {"Column_14",3},
                                                      {"Column_12",4},
                                                      {"Column_34",5},
                                                      {"Column_78",6},
                                                      {"Column_54",7},
                                                      {"Column_88",8},
                                                      {"Column_98",9},
                                                      {"Column_90",10},
                                                      {"Column_51",11},
                                                      {"Column_100",12},
                                                      {"Column_35",13},
                                                      {"Column_112",14},
                                                      {"Column_101",15}
                                                  };
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MyClassViewModel();
    }

    /// <summary>
    /// Toggle display of only subset of columns
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        if (ApplyColumns.IsChecked ?? false)
        {
            foreach (var col in this.Grid.Columns)
            {
                if (_predefinedColumns.ContainsKey(col.Header as string))
                {
                    col.Visibility = Visibility.Visible;
                    col.DisplayIndex = _predefinedColumns[col.Header as string];
                }
                else
                {
                    col.Visibility = Visibility.Collapsed;
                }
            }
        }
        else
        {
            foreach (var col in this.Grid.Columns)
            {
                col.Visibility = Visibility.Visible;
                var header = col.Header.ToString();
                col.DisplayIndex = Int32.Parse(header.Substring(7)) - 1;
            }
        }
    }
}

Эта вью-модель воспроизводит большие данные, используя созданную вручную DataTable. Однако в реальном коде datagrid привязывается к классу с динамическим свойством, добавленным с помощью typedescripter

    public class MyClassViewModel
{
    public DataView MyDataView
    {
        get
        {
            var dt = new DataTable();
            foreach (var colNum in Enumerable.Range(1, 120))
            {
                dt.Columns.Add(String.Format("Column_{0}", colNum), Type.GetType("System.Int32"));
            }

            var r = new Random();
            for (int x = 1; x <= 1000; x++)
            {
                var dr = dt.NewRow();
                foreach (var colNum in Enumerable.Range(1, 120))
                {
                    dr[String.Format("Column_{0}", colNum)] = r.Next(100);
                }
                dt.Rows.Add(dr);
            }
            return dt.DefaultView;
        }
    }
}

Я пробовал следующее, но пока безуспешно

1. Производительность повышается, если я включаю виртуализацию строк и столбцов. Однако это ухудшает производительность прокрутки, что неприемлемо (особенно если вы пытаетесь перетащить большой палец).
2. Вместо изменения отображения и видимости я попробовал удалить все столбцы, а затем добавить только нужные, но это также не повлияло на производительность.

Я буду очень признателен за любую помощь в этом вопросе. Мы не хотим получить прирост производительности за счет ухудшения работы прокрутки. Итак, если виртуализация должна быть включена, как мы можем улучшить производительность прокрутки. Или есть какой-нибудь лучший способ добиться как хорошей производительности прокрутки, так и хорошей производительности показа/скрытия/перемещения колонок с такими большими массивами данных.

9
задан shomat 1 December 2011 в 15:12
поделиться