【发布时间】:2021-10-10 00:18:30
【问题描述】:
我喜欢this 的解决方案方法,但它不适用于虚拟化。
这是该帖子中的相关代码,缩写:
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
DataRowView dataRow = (dataItem as DataRowView);
object cellData = dataRow[cell.Column.DisplayIndex];
var contentHost = new ContentControl() { Content = cellData };
contentHost.ContentTemplate = (DataTemplate)SomeResourceDictionary["SomeResourceKey"];
return contentHost;
}
DataGrid 为每个创建/渲染的单元格调用此方法。如果启用了虚拟化,那么这里创建的FrameworkElement可能会被回收,即再次使用。
问题:使用存储在cell 和dataItem 中的信息确定内容,并将直接引用传递给创建的ContentControl。如果这个FrameworkElement 被重用,它将引用相同的内容——不管它被渲染到哪一行。
结果:在(快速)滚动期间,网格行中显示的内容会随机混合。
我的问题:使用cell.Column.DisplayIndex 可以设置ContentControl.Content 绑定而不包括对所需内容的直接引用吗?也许,就好像我在 Xaml 中这样定义它:"{Binding Path=dataRow[0]}" - 但这似乎也不太正确。
任何建议都非常感谢!
@BionicCode:
这里解决了两个挑战:
- 将
DataGrid绑定到具有动态列的源。 - 允许为每个动态生成的列定义
DataTemplate。
上面链接的帖子很好地涵盖了第一个问题:从原始源创建一个DataTable 并将DataGrid 绑定到它。第二个问题的困难部分——以及为什么不能简单地使用DataGridTemplateColumns——是DataGridTemplateColumns 接收整个行项作为数据上下文,即要访问正确的数据,模板必须知道它是哪一列用于。
这就是上面显示的代码解决方案的用武之地,通过手动生成 FrameworkElement 并“静态”分配所需的内容。
幸运的是,修复相当简单,请参阅下面的答案。
【问题讨论】:
-
不清楚你到底想要达到什么目的。
-
如果我遵循正确,我将更有可能构建数据网格列定义的集合。 Xamlreader.parse 将每个字符串解析为一列。
-
@andy 你能解释一下“Xamlreader.parse a string for each into a column”是什么意思吗?
-
@andy 如果您查看我的回答,您认为您的方法的性能与我的相比如何?
-
Var newcolumndefinition=Xamlreader.parse(thestring);允许您将 ui 构建为字符串并将其解析为 ui 对象。不是在编译时定义的数据网格中的固定列,而是在运行时动态地做同样的事情。我在 technet 上有一个 repo 说明了这一点,但 ms 将 technet wiki 存储库分箱。性能应该会好很多。