如何动态设置 WPF DataGridCell 样式
我有一个 DataGrid,其 itemsSource 定义如下:
dg.ItemsSource = new ObservableCollection<myRow>
...
public class myRow : Collection<myDataGridCell> { ... }
...
public interface ImyDataGridCell
{
Brush Background { get; set; }
Brush Foreground { get; set; }
}
然后我为每种类型的列/单元格设置了类:
public class myTextBoxColumn : DataGridTextColumn {...}
public class myTextBoxCell : TextBox, ImyDataGridCell {...}
然后我像这样设置每列的 CellStyle :
在每列的构造函数中:
string source = String.Format(CultureInfo.InvariantCulture, "[{0}].", dataGrid.Columns.Count);
// I set the "source" string to the column's index in the dataGrid's Columns list between [] to get an index in my binding below.
CellStyle = new Style(typeof(DataGridCell));
CellStyle.Setters.Add(new Setter(DataGridCell.BackgroundProperty, new Binding(source + "Background")));
这允许我绑定实际的 DataGridCell 的背景属性到我的单元格表示的背景属性,从而可以随时轻松地修改单元格的背景。
现在我的主要问题是这种做事方式会减慢 dataGrid 的速度...... 我为每个单元格绑定了大约 15 个属性,当我显示 100 列 x 20 行时,需要超过一秒的时间来显示 dataGrid,然后在水平滚动时大约需要一秒的时间来刷新它(我的屏幕只能允许 20一次 cols,并且我为 dataGrid 启用了虚拟化)。
如果我去掉样式,响应时间仍然比我想要的要长,但我可以用它来做。
那么有没有更好的方法来做到这一点呢?
我也尝试在 Xaml 中执行此样式,但它似乎不能很好地应对列的虚拟化,即:我将单元格的背景设置为绿色,然后向右滚动整个页面,并且单元格最终位于与我涂成绿色的单元格如果应该是红色的话就会得到绿色事件:直到我将当前行移动到包含该单元格的行为止,该值不会更新... 另外,它似乎根本没有提高性能...
感谢分享,如果您对此事有任何想法/提示/以前的经验,我愿意尝试一切可以使该死的 dataGrid 加载速度更快的方法。 ..
编辑:我想要实现的一般效果:
- 具有动态列的数据网格(列的数量和类型仅在运行时
- 随时知道,我可以更改单个单元格的任何样式属性:字体(系列、大小、样式、粗细、装饰(如果应用))、前景、背景、文本对齐(如果有的话)等......
这正是我必须实现的目标。 我知道我发现在启用列虚拟化的情况下,您无法操作真实的 dataGridCells,因为它们可能尚未显示(虚拟化),然后您会丢失属性值的更改。因此,我采用了这一“技巧”:将实际 dataGridCell 样式中的每个属性绑定到“逻辑”属性,然后修改逻辑属性。但这太慢了。
希望我能更好地解释自己。
I have a DataGrid with the itemsSource defined as follow:
dg.ItemsSource = new ObservableCollection<myRow>
...
public class myRow : Collection<myDataGridCell> { ... }
...
public interface ImyDataGridCell
{
Brush Background { get; set; }
Brush Foreground { get; set; }
}
and then I have classes for each type of column/cell:
public class myTextBoxColumn : DataGridTextColumn {...}
public class myTextBoxCell : TextBox, ImyDataGridCell {...}
then I set each column's CellStyle like this:
in each column's constructor:
string source = String.Format(CultureInfo.InvariantCulture, "[{0}].", dataGrid.Columns.Count);
// I set the "source" string to the column's index in the dataGrid's Columns list between [] to get an index in my binding below.
CellStyle = new Style(typeof(DataGridCell));
CellStyle.Setters.Add(new Setter(DataGridCell.BackgroundProperty, new Binding(source + "Background")));
this allows me to bind the actual DataGridCell's Background property to the Background property of my cell's representation, and thus to modify a cell's background anytime I want easily.
now my main issue is that this way of doing things slows the dataGrid like hell...
I have around 15 properties I bind for each cell, and when I show 100 cols x 20 rows it takes more than a second to show the dataGrid and then about a second to refresh it when I scroll horizontally (my screen can only allow for 20 cols at a time, and I have Virtualization enabled for the dataGrid).
If I get rid of the styling, the response time is still more than I'd like, but I could do with it.
So is there a better way to do this?
I also tried doing this style in Xaml, but It did not seem to cope well with column's virtualization, i.e.: I would set a cell's background green, then scroll a whole page right, and the cell that ends up in the same position as the cell I had painted green gets the green color event if it should be red: the value is not updated untill I move the current row to the row containing the cell...
plus, it did not seem to improve performance at all...
thanks for sharing if you have any kind of though/tip/previous experience on the matter, I'm willing to try about everything that could make this damn dataGrid load faster...
Edit: General effect I want to achieve:
- a dataGrid with dynamics columns (the number and type of columns are only known at runtime
- at any time, I can change whatever style property of a single cell: Font (family, size, style, weight, decoration if applied), foreground, background, textAlignment if any etc...
this is just what I have to achieve.
know I found that with column virtualization on, you cannot manipulate the REAL dataGridCells, as they might not be shown yet (virtualized), and then you loose the property value's change. So I went for this "hack": I bind every single property in the actual dataGridCell's style to the "logical" one, and I modify the logical one. But this is slooooow.
hope I managed to explain myself a little better.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有机会看到你缓慢的 Xaml 吗?我本以为使用数据触发器执行此操作不会太糟糕(而且您使用哪个版本的数据网格,因为 .net 4.0 和 WPF Toolkit 版本是不同的)
我已经做了类似的事情来重新着色选定的项目,它看起来并不太慢(这不是正确的解决方案,但在我说更多之前我想了解更多细节):
Any chance of seeing your slow Xaml? I would have thought that doing this with a datatrigger wouldn't be too awful (also which version of the data grid are you using as the .net 4.0 and the WPF Toolkit versions are different)
I've done stuff like this to recolor for selected items and it didn't seem too slow (this isn't the right solution but I'd like a little more detail before I say any more):