Связывание DataGrid Cell.Style - PullRequest
       9

Связывание DataGrid Cell.Style

1 голос
/ 23 ноября 2010

У меня проблема с производительностью в WPF DataGrid (.net 4.0). Сначала

, некоторые детали:

  • У меня есть сетка данных с наблюдаемой коллекцией как ItemsSource.
  • эта observableCollection сама содержит коллекции объектов, каждая коллекция, следовательно, является строкой, каждый объект является ячейкой («логическая» ячейка, конечно, не фактическая dataGridCell)

причина, по которой я это делаюэто потому, что я знаю только во время выполнения, сколько столбцов у меня будет в моей dataGrid.

  • , тогда я привязываю значение каждого DataGridCell к значению объекта в «логической» таблице (= коллекцияколлекции)

теперь у меня проблема в том, что я также должен иметь возможность изменять любые свойства ячейки (например, Background, Foreground, FontFamily и т. д.) в любое время, пока приложение работает.

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

здесь IПример кода (в моем приложении нет Xaml):

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Width = 1200;
        Height = 780;
        Top = 60;
        Left = 200;

        DataGrid dg = new DataGrid();
        Content = dg;

        ObservableCollection<Row> Source = new ObservableCollection<Row>();
        dg.ItemsSource = Source;

        dg.SelectionMode = DataGridSelectionMode.Extended;
        dg.IsSynchronizedWithCurrentItem = true;

        dg.CanUserSortColumns = false;
        dg.CanUserReorderColumns = true;
        dg.CanUserResizeColumns = true;
        dg.CanUserResizeRows = true;
        dg.CanUserAddRows = false;
        dg.CanUserDeleteRows = false;

        dg.AutoGenerateColumns = false;

        dg.EnableColumnVirtualization = true;
        dg.EnableRowVirtualization = false;     // unuseful in my case : I alawys have less lines than the DG can contain

        dg.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
        dg.GridLinesVisibility = DataGridGridLinesVisibility.None;
        dg.HorizontalGridLinesBrush = Brushes.LightGray;

        dg.MinRowHeight = 20;
        dg.RowHeaderWidth = 20;

        for (int i = 0; i < 100; i++)
        {
            DataGridTextColumn column = new DataGridTextColumn();
            column.Binding = new Binding(String.Format(CultureInfo.InvariantCulture, "[{0}].Text", i));
            Style style = new Style(typeof(DataGridCell));
            style.Setters.Add(new Setter(DataGridCell.BackgroundProperty, new Binding(String.Format(CultureInfo.InvariantCulture, "[{0}].Background", i))));
            style.Setters.Add(new Setter(DataGridCell.ForegroundProperty, new Binding(String.Format(CultureInfo.InvariantCulture, "[{0}].Foreground", i))));
            column.CellStyle = style;
            column.Header = "Column " + i;
            dg.Columns.Add(column);
        }

        for (int i = 0; i < 35; i++)
        {
            Row dgRow = new Row();
            Source.Add(dgRow);
            for (int j = 0; j < 100; j++)
                dgRow.Add(new TextBox() { Text = "cell " + i + "/" + j, Background = Brushes.AliceBlue, Foreground = Brushes.BlueViolet });
        }
    }
}

public class Row : ObservableCollection<TextBox>
{
}

Моя проблема: при включенном VolumnVirtualisation (виртуализация строк в моем случае не требуется), для загрузки сетки требуется около 2 секунд, изатем 1 с каждый раз, когда я перемещаю горизонтальную полосу прокрутки большим скачком (щелкает полосу прокрутки bg, а не стрелку)

, это слишком много для моей цели

, поэтому мой вопрос: ячто-то не так и если да, то что?какой лучший способ сделать это у меня есть?

спасибо за чтение

Ответы [ 2 ]

1 голос
/ 23 ноября 2010

Если ColumnVirtualization создает такие проблемы, зачем вам это нужно? Вы можете сделать несколько улучшений, но они не могут полностью решить проблему.

  1. Изменить текстовые поля для легких объектов:

    public class TextItem
    {
        public string Text { get; set; }
        public Brush Background { get; set; }
        public Brush Foreground { get; set; }
    }
    
    
    public class Row : ObservableCollection<TextItem>
    {
    }
    
  2. Включить VirtualizingStackPanel: dg.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, true);

  3. Заменить стили на шаблоны:

        for (int i = 0; i < 100; i++)
        {
            DataGridTemplateColumn column = new DataGridTemplateColumn();
            column.CellTemplate = (DataTemplate)XamlReader.Parse(
                "<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" +
                    "<TextBlock DataContext='{Binding [" + i + "]}' Text='{Binding Text}' Background='{Binding Background}' Foreground='{Binding Foreground}'/>" +
                "</DataTemplate>");
            column.Header = "Column " + i;
            dg.Columns.Add(column);
        }
    
0 голосов
/ 17 февраля 2011

Потратив много времени на это, я пришел к выводу, что достиг предела.

Вот несколько мыслей для тех, кто имеет дело с той же проблемой:

  1. Начиная с .net 4.0, не существует простого способа управления визуальными свойствами отдельной ячейки в .net 4.0: MS не планировала ничего сделать, чтобы упростить эту задачу, поэтому, по сути, у вас есть две возможности сделать это:

    • получить фактический dataGridCell, используя какую-то вспомогательную функцию, а затем напрямую изменить его свойства.Это легко сделать, но может привести к большим проблемам, если виртуализация включена.
    • привязывает визуальные свойства каждой ячейки к свойствам зависимости от вашей виртуальной машины внутри стиля dataGridCell.Вы можете использовать либо DataGrid.CellStyle, либо Column.CellStyle, чтобы сделать это, в зависимости от ваших ограничений.Это немного замедляет dataGrid, и это довольно хлопотно для управления.
  2. если, как и у меня, у вас нет выбора, кроме как использовать второй вариант (потому что мне нужна виртуализация), вот несколько вещей, которые следует учитывать:

    • Вы не застряли с C #.На самом деле есть способ сделать ваш CellStyle в Xaml.Смотрите сообщение Мартино по этому вопросу .Насколько я понимаю, это работает довольно хорошо.Я немного подправил его, чтобы не использовать хак: хотя я определяю свой стиль в Xaml и применяю его к Column.CellStyle.Затем, когда я создаю столбец в своем коде, я просто создаю новый стиль, наследующий этот, и добавляю установщик тегов с привязкой, установленной в: «[Index of column] .Self».Это нарушает модель MVVM, но я все равно ее не использую, и проще поддерживать таким образом.
    • Очевидно, чем больше свойств вы должны связать, тем больше времени потребуется для загрузки вашей dataGrid,так что придерживайтесь минимума (использование легких объектов действительно имеет небольшое значение, как заявлено Vorrtex).
    • , в то время как использование шаблонов или стилей абсолютно не влияет на производительность, если вы используете dataGridTemplateColumns, вы быочевидно, что вам нужно установить привязки непосредственно в шаблоне вместо добавления стиля поверх шаблона (это имеет небольшое значение при огромном количестве данных)

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

...