如何获取发送路由事件的控件的父控件的列索引

本文关键字:控件 事件 索引 路由 何获取 获取 | 更新日期: 2023-09-27 18:20:07

我的表单上有一个带有ButtonUserControl,单击它时,会在新行或列中添加UserControl或不同UserControl的另一个实例。我想做的是,当单击Button时,找出包含ButtonUserControl在哪个列中,然后将新的UserControl添加到同一列中。代码如下:

        ++rowCount;
        int currentColumn = Grid.GetColumn(e.Source as UIElement);
        AnswerNode answerNode = new AnswerNode();
        answerNode.buttonAddQuestionNode.MouseLeftButtonDown += AddQuestionNode_DifferentLevelEvent;
        answerNode.Margin = new Thickness(0, 5, 0, 5);
        RowDefinition gridRowNew = new RowDefinition();
        gridRowNew.Height = new GridLength(70);
        Grid.SetRow(answerNode, rowCount);
        Grid.SetColumn(answerNode, currentColumn);
        MainGrid.RowDefinitions.Add(gridRowNew);
        MainGrid.Children.Add(answerNode);

我遇到的问题是,获取e.Source的列索引会导致UserControl中按钮的索引—在这种情况下为CCD_ 11—而不是CCD_ 12本身的列索引。我将如何访问UserControl的列索引,它是被单击的Button的父级?

如何获取发送路由事件的控件的父控件的列索引

如果没有一个好的、最小的complete代码示例来清楚地说明问题,准确地显示您尝试了什么以及希望事件处理如何工作,很难确定最佳答案是什么。也就是说,从您提供的小代码和问题描述来看,听起来您订阅了错误控件对象中的事件。具体来说,您已经在Button对象中直接声明了事件处理程序,而不是在UserControl中订阅Button.Click事件。

对于路由的事件,您总是可以获得事件的原始源,即通过RoutedEventArgs.OriginalSource属性最初用信号通知事件的控件。RoutedEventArgs.Source属性反过来将提供对事件已路由到的控制对象的引用,并且当前正在处理该事件。如果要处理UserControl对象看到的事件,则需要从UserControl对象而不是Button对象订阅事件。

下面是一个简短、完整的代码示例,说明了基本技术:

XAML:

用户控制1.xaml

<UserControl x:Class="TestSO33441926RoutedEvent.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <TextBlock Text="Click here: "/>
    <Button x:Name="button1" Content="Click me!" Grid.Column="1"
            HorizontalAlignment="Left" VerticalAlignment="Top"
            Click="Button_Click"/>
  </Grid>
</UserControl>

主窗口.xaml

<Window x:Class="TestSO33441926RoutedEvent.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:TestSO33441926RoutedEvent"
        Title="MainWindow" Height="350" Width="525">
  <Grid x:Name="grid1">
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
      <ColumnDefinition/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <TextBlock Text="MainWindow column 1"/>
    <TextBlock Text="MainWindow column 2" Grid.Column="1"/>
    <l:UserControl1 x:Name="userControl1" Grid.Column="2"
                    Button.Click="UserControl1_Click"/>
  </Grid>
</Window>

C#:

UserControl1.xaml.cs

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        App.ReportClick((FrameworkElement)e.Source);
    }
}

主窗口.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private void UserControl1_Click(object sender, RoutedEventArgs e)
    {
        App.ReportClick((FrameworkElement)e.Source);
    }
}

App.xaml.cs

public partial class App : Application
{
    public static void ReportClick(
        FrameworkElement frameworkElement, [CallerMemberName]string callerName = null)
    {
        MessageBox.Show(
            "Caller name: '"" + callerName + "'"'n" +
            "Sender name: '"" + frameworkElement.Name + "'"'n" +
            "Sender column: " + Grid.GetColumn(frameworkElement));
    }
}

由于两个事件处理程序都未将RoutedEventArgs.Handled设置为true,因此事件将依次发送到每个处理程序,从事件的原始源开始,然后在视觉对象图中依次向上移动到每个父级。

因此,您可以看到,当每个事件处理程序调用ReportClick()方法时,e.Source对象在各个事件处理程序中是不同的,这取决于该处理程序的订阅位置。

对于您自己的问题,关键在这里,在MainWindow.xaml源代码中:

    <l:UserControl1 x:Name="userControl1" Grid.Column="2"
                    Button.Click="UserControl1_Click"/>

请注意,Button.Click事件是正在订阅的事件,但代码是从UserControl1对象订阅。其结果是调用事件处理程序void UserControl1_Click(object, RoutedEventArgs),并将UserControl1对象作为事件的发送方和源。

因此,当通过调用Grid.GetColumn(UIElement)来检索事件的发送方的列索引时,返回的是UserControl1对象的列索引,而不是事件的原始源(即实际单击的Button对象)的列索引。


顺便说一句:在你的帖子显示的代码中,似乎有相当多的代码可以更好地实现为XAML声明。当然,在XAML中可以做的任何事情,也可以在代码背后完成。但这并不意味着这是个好主意。解决代码中的缺陷不太可能与您提出的问题直接相关,以这种方式更改实现也不会解决问题。但是,您绝对应该认真考虑更紧密地遵循WPF/XAML范式,并尽可能多地将您的实现放在XAML中