如何从 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;
}

虽然此解决方案有效并且是解决问题的合法且正式记录的方法,但您通常不必以这种方式遍历可视化树。在大多数情况下,这不是必需的,因为使用数据绑定可以更优雅、更轻松地解决很多问题。