DataGrid Cell.Style绑定

我有WPF DataGrid(.net 4.0)的性能问题

首先,一些细节:

  • 我有一个带有Observable集合的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 Source = new ObservableCollection(); 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 { } 

我的问题是:使用VolumnVirtualisation On(在我的情况下我不需要行虚拟化),网格需要大约2秒才能加载,然后每次移动水平滚动条大幅跳跃1秒(滚动条bg中的clic,不是箭头)

这对我来说太过分了

所以我的问题是:我做错了什么,如果是的话,是什么? 我有更好的方法吗?

谢谢阅读

如果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 { } 
  2. 启用VirtualizingStackPanel: dg.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, true);

  3. 用模板替换样式:

      for (int i = 0; i < 100; i++) { DataGridTemplateColumn column = new DataGridTemplateColumn(); column.CellTemplate = (DataTemplate)XamlReader.Parse( "" + "" + ""); column.Header = "Column " + i; dg.Columns.Add(column); } 

经过大量的时间投入,我得出结论,我已达到极限。

以下是处理同一问题的人的一些想法:

  1. 从.net 4.0开始,没有简单的方法可以在WPF中管理单个单元格的视觉属性:MS没有计划任何事情来简化这一点,所以基本上你有两种可能性来做到这一点:

    • 使用某种辅助函数获取实际的dataGridCell,然后直接更改其属性。 这很容易完成,但如果打开虚拟化可能会导致大麻烦。
    • 将每个单元格的可视属性绑定到dataGridCell样式中VM的依赖属性。 您可以使用DataGrid.CellStyle或Column.CellStyle来执行此操作,具体取决于您的约束。 这会使dataGrid相当缓慢,并且管理起来非常麻烦。
  2. 如果像我一样你别无选择,只能使用第二种选择(因为我需要虚拟化),这里有几点需要考虑:

    • 你不会被C#困住。 实际上有一种方法可以在Xaml中进行CellStyle。 请参阅Martino关于此问题的post 。 就我而言,这非常有效。 我稍微调整了一下,以便不必使用hack:我在Xaml中定义我的样式并将其应用于Column.CellStyle。 然后当我在我的代码后面创建一个列时,我只是创建一个inheritance这个列的新样式,然后我添加一个带有绑定集的Tag setter:“[column’s Index] .Self”。 这打破了MVVM模型,但我还没有使用它,而且这样更容易维护。
    • 显然,你必须绑定的属性越多,你的dataGrid加载所需的时间就越多,所以坚持最小(使用轻量级对象确实会产生一些小的差异,如Vorrtex所述)。
    • 虽然使用模板或样式在性能方面没有任何区别,但是如果你使用的是dataGridTemplateColumns,你需要直接在模板中设置绑定,而不是在模板顶部添加样式,这显然会产生很小的差异有大量数据)

如果有人要添加任何东西,请这样做! 我仍然在寻找可以改善现状的任何想法,并且对于你对这个主题的任何疯狂想法感到高兴。 即使在3个月……