2010-11-23 6 views
1

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

первым, некоторыми деталями:

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

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

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

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

Решения, которое я придумал это один с участием установки cellStyles с креплениями, которые связываются с „Логической“ клеткой столбцы свойств

здесь пример кода (не 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 On (мне не нужна строка виртуализации в моем случае), сетка занимает около 2 секунд для загрузки, а затем 1сек каждый раз, когда я перемещаю горизонтальную полосу прокрутки большим прыжком (clic in scrollBar bg, а не стрелка)

t его слишком много для моей цели

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

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

ответ

0

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

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

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

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

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

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

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

1

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

  1. Изменение TextBoxes для легкого веса объектов:

    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. Replace стилей с шаблонами:

    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

благодарит за ваш ответ. У меня есть вопрос: как шаблон шаблона будет лучше, чем стиль для каждой ячейки? (Я бы подумал, что это была полная противоположность) – David 2010-11-23 17:03:10

+1

Потому что у DataGridTextColumn уже есть шаблон, поэтому столбец с шаблоном лучше, чем столбец с шаблоном и стилем. По крайней мере, я так думаю, и это логично для меня. – vorrtex 2010-12-03 15:07:59

Смежные вопросы