如何从 Click 事件中找到 DataTemplate 控件
How to find a DataTemplate control from inside the Click event
我有一个 GridView
和一个 ColumnHeaderTemplate
模板包含名称为 arrow
:
的路径
<DataTemplate x:Key="HeaderTemplate">
<DockPanel>
<Path DockPanel.Dock="Right" Margin="5,0,5,0" x:Name="arrow" StrokeThickness="1" Fill="Gray" Data="M 5,5 L 10,10 L 15,5 L 5,5" SnapsToDevicePixels="True"/>
</DockPanel>
</DataTemplate>
模板在视图中分配如下:
<GridView ColumnHeaderTemplate="{StaticResource HeaderTemplate}">
GridView
位于管理事件的 ListView
中
GridViewColumnHeader.Click="ListView_ColumnHeaderClick"
private void ListView_ColumnHeaderClick(object sender, RoutedEventArgs e)
当事件被触发时,我希望能够找到 arrow
控件。
根据我的研究,我应该使用 Template.FindName
方法,但到目前为止我还没有能够做到这一点。
我似乎无法找到与函数一起使用的正确对象,因此我从未找到我正在寻找的控件。
不,您所说的 FindName
方法适用于 ControlTemplate
,而不适用于 DataTemplate
。
对于 DataTemplate
,您必须使用 VisualTreeHelper
.
手动迭代 children
我不知道你是如何附加列 header 事件处理程序的,所以我假设是这样的:
<ListView ItemsSource="{Binding YourItemsSource}">
<ListView.Resources>
<DataTemplate x:Key="HeaderTemplate">
<DockPanel>
<Path DockPanel.Dock="Right" Margin="5,0,5,0" x:Name="arrow" StrokeThickness="1" Fill="Gray" Data="M 5,5 L 10,10 L 15,5 L 5,5" SnapsToDevicePixels="True"/>
</DockPanel>
</DataTemplate>
<Style x:Key="HeaderContainerStyle" TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource {x:Type GridViewColumnHeader}}">
<EventSetter Event="Click" Handler="ListView_ColumnHeaderClick"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView ColumnHeaderTemplate="{StaticResource HeaderTemplate}"
ColumnHeaderContainerStyle="{StaticResource HeaderContainerStyle}">
<!-- ...your column definitions. -->
</GridView>
</ListView.View>
</ListView>
您必须创建一个自定义方法来递归遍历网格视图列 header 的可视化树,检查 child 元素的类型和名称以获得正确的元素。
public T GetChild<T>(DependencyObject dependencyObject, string name) where T : FrameworkElement
{
if (dependencyObject == null)
return null;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
if (child is T frameworkElement && frameworkElement.Name.Equals(name))
return frameworkElement;
var nextChild = GetChild<T>(child, name);
if (nextChild != null)
return nextChild;
}
return null;
}
然后在事件处理程序中,您可以传递 sender
,即 header.
列
private void ListView_ColumnHeaderClick(object sender, RoutedEventArgs e)
{
var gridViewColumnHeader = (GridViewColumnHeader)sender;
var arrow = GetChild<Path>(gridViewColumnHeader, "arrow");
// ... do something with arrow.
return;
}
虽然此解决方案有效并且是解决问题的合法且正式记录的方法,但您通常不必以这种方式遍历可视化树。在大多数情况下,这不是必需的,因为使用数据绑定可以更优雅、更轻松地解决很多问题。
我有一个 GridView
和一个 ColumnHeaderTemplate
模板包含名称为 arrow
:
<DataTemplate x:Key="HeaderTemplate">
<DockPanel>
<Path DockPanel.Dock="Right" Margin="5,0,5,0" x:Name="arrow" StrokeThickness="1" Fill="Gray" Data="M 5,5 L 10,10 L 15,5 L 5,5" SnapsToDevicePixels="True"/>
</DockPanel>
</DataTemplate>
模板在视图中分配如下:
<GridView ColumnHeaderTemplate="{StaticResource HeaderTemplate}">
GridView
位于管理事件的 ListView
中
GridViewColumnHeader.Click="ListView_ColumnHeaderClick"
private void ListView_ColumnHeaderClick(object sender, RoutedEventArgs e)
当事件被触发时,我希望能够找到 arrow
控件。
根据我的研究,我应该使用 Template.FindName
方法,但到目前为止我还没有能够做到这一点。
我似乎无法找到与函数一起使用的正确对象,因此我从未找到我正在寻找的控件。
不,您所说的 FindName
方法适用于 ControlTemplate
,而不适用于 DataTemplate
。
对于 DataTemplate
,您必须使用 VisualTreeHelper
.
我不知道你是如何附加列 header 事件处理程序的,所以我假设是这样的:
<ListView ItemsSource="{Binding YourItemsSource}">
<ListView.Resources>
<DataTemplate x:Key="HeaderTemplate">
<DockPanel>
<Path DockPanel.Dock="Right" Margin="5,0,5,0" x:Name="arrow" StrokeThickness="1" Fill="Gray" Data="M 5,5 L 10,10 L 15,5 L 5,5" SnapsToDevicePixels="True"/>
</DockPanel>
</DataTemplate>
<Style x:Key="HeaderContainerStyle" TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource {x:Type GridViewColumnHeader}}">
<EventSetter Event="Click" Handler="ListView_ColumnHeaderClick"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView ColumnHeaderTemplate="{StaticResource HeaderTemplate}"
ColumnHeaderContainerStyle="{StaticResource HeaderContainerStyle}">
<!-- ...your column definitions. -->
</GridView>
</ListView.View>
</ListView>
您必须创建一个自定义方法来递归遍历网格视图列 header 的可视化树,检查 child 元素的类型和名称以获得正确的元素。
public T GetChild<T>(DependencyObject dependencyObject, string name) where T : FrameworkElement
{
if (dependencyObject == null)
return null;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
if (child is T frameworkElement && frameworkElement.Name.Equals(name))
return frameworkElement;
var nextChild = GetChild<T>(child, name);
if (nextChild != null)
return nextChild;
}
return null;
}
然后在事件处理程序中,您可以传递 sender
,即 header.
private void ListView_ColumnHeaderClick(object sender, RoutedEventArgs e)
{
var gridViewColumnHeader = (GridViewColumnHeader)sender;
var arrow = GetChild<Path>(gridViewColumnHeader, "arrow");
// ... do something with arrow.
return;
}
虽然此解决方案有效并且是解决问题的合法且正式记录的方法,但您通常不必以这种方式遍历可视化树。在大多数情况下,这不是必需的,因为使用数据绑定可以更优雅、更轻松地解决很多问题。