我将展示如何在运行时探究 GridViewColumn 和 GridViewRowPresenter 交互。考虑以下简化的 XAML:
<ListView x:Class="demo_listview"
xmlns="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wd="clr-namespace:System.Windows.Documents;assembly=PresentationFramework"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<!-- ... -->
<ListView.View>
<GridView>
<!-- ... -->
<GridViewColumn x:Name="my_gv_column" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="my_textblock" Text="ABCD" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!-- ... -->
</GridView>
</ListView.View>
</ListView>
现在在代码中,重写诸如ListView.ClearContainerForItemOverride 之类的方法,如下所示。代码会修改TextBlock的背景色,使其变为红色:
请注意,由于容器被回收,红色在“清理”后仍然存在。我选择该函数是为了保持演示简单,因为它确保模板将被完全实例化以供检查。否则,例如,如果您得到 gv_row 的“null”,则需要立即调用 lvi.ApplyTemplate()。
我假设您能够轻松地为您感兴趣的行获取ListViewItem。因此,从运行时任何完全实例化的ListViewItem,我们现在可以看到如何获取特定的内容在运行时实例化CellTemplate。附加说明在代码下方。
public partial class demo_listview : ListView
{
protected override void ClearContainerForItemOverride(DependencyObject el, object item)
{
base.ClearContainerForItemOverride(el, item);
var lvi = (ListViewItem)el;
var gv_row = (GridViewRowPresenter)lvi.Template.FindName("5_T", lvi);
var ix = ((GridView)View).Columns.IndexOf(my_gv_column);
var cp = (ContentPresenter)VisualTreeHelper.GetChild(gv_row, ix);
var tb = (TextBlock)my_gv_column.CellTemplate.FindName("my_textblock", cp);
tb.Background = Brushes.Red;
}
};
第一步是从ListViewItem 获取GridViewRowPresenter。有几种方法可以做到这一点。上面,我使用魔术常量“5_T”从模板名称中获取实例化。此常量由 WPF 定义,因此只要您使用标准的ListViewItem 其内置控件模板,它就可以工作。
接下来我们需要我们感兴趣的列的索引。在 C# 中通过在 XAMLmy_gv_column) 可以轻松访问列实例本身/强>。至于它的索引,我不确定如果列重新排序,这里显示的IndexOf 技术是否会继续工作。如果不是,则可以通过反射从感兴趣的GridViewColumn 获取私有_actualIndex 字段(或ActualIndex 属性)的值来获得正确的结果。
接下来,使用VisualTreeHelper.GetChild,获取与所需列索引相对应的GridViewRowPresenter 的可视子项;这将是单元格的ContentPresenter!有了这个,您可以在模板中进行另一个FindName 搜索,以按名称查找您正在寻找的实际实例化控件。在示例中,我们成功获取了TextBlock 实例,然后更改其背景颜色以演示结果。