【问题标题】:Event of clicking on buttons in the ContentControl单击 ContentControl 中的按钮的事件
【发布时间】:2020-07-24 14:28:52
【问题描述】:

研究模板时,我对如何获取单击此或那个模板按钮的事件很感兴趣。以简单模板为例:

<Window.Resources>
    <ControlTemplate x:Key="ControlTemplateKey" TargetType="{x:Type ContentControl}">
        <StackPanel>
            <TextBlock Text="TextBlock 01" />
            <Button Content="Button 01" />
            <Button Content="Button 02" />
        </StackPanel>
    </ControlTemplate>
</Window.Resources>

<ContentControl x:Name="ContentControlName" Template="{StaticResource ControlTemplateKey}" />

为了确定点击一个或另一个元素(在本例中为按钮),我遍历树的内容:

ContentControlName.PreviewMouseDown += (s, e) =>
{
    DependencyObject i = VisualTreeHelper.HitTest(s as Visual, Mouse.GetPosition(s as IInputElement)).VisualHit;

    while (i != null)
    {
        if (i is Button)
        {
            Console.WriteLine((i as Button).Content);
            break;
        }

        i = VisualTreeHelper.GetParent(i);
    }
};

但是,我认为有一种专门针对此的更简单的方法,而不是我在树上的迭代。如何更轻松地识别模板中按下的按钮?谢谢

【问题讨论】:

  • 点击按钮会发生什么?你真的不需要 hit tests 按钮。它们已经支持命令,您可以将其绑定到 ICommand 属性。
  • 谢谢。当你按下这个或那个按钮时,会出现一个特定的代码。 Sinatr,你的意思是这样的c-sharpcorner.com/UploadFile/e06010/wpf-icommand-in-mvvm
  • 你用这样的模板做什么?比方说你如何为一个ContentControl实例定义Text = "TextBlock 01" 值。还是它们都一样?通常,元素的数据提供者是 DataContext,并且通过绑定从中检索数据。例如 Text = "{Binding Text01}"。因此,最正确的方法是使用@Sinatr 所写的命令。
  • 是的,这是一个正确的说法,我没有在问题中指出模板重复使用不同的元素属性,这些属性是通过Binding设置的。我专注于事件。我从 EldHasp 那里得到了很好的回答——通过 Command 访问。

标签: c# wpf templates button


【解决方案1】:

如果您需要 MVVM 模式之外的解决方案,您仍然可以使用命令冒泡。 为此,使用了 RoutedCommand 类。

<Window x:Class="ClickInTemplate.ClickWind"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ClickInTemplate"
        mc:Ignorable="d"
        Title="ClickWind" Height="450" Width="800">
    <Window.Resources>
        <ControlTemplate x:Key="ControlTemplateKey" TargetType="{x:Type ContentControl}">
            <StackPanel>
                <TextBlock Text="TextBlock 01" />
            
                <!--Any data can be passed in the parameter.
                In this example, I am passing in the parent ContentControl.-->
                <Button Content="Button 01" Command="Find"
                        CommandParameter="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}}"/>

                <!--In this example, I am passing just text.-->
                <Button Content="Button 02" Command="Cut"
                        CommandParameter="The button was pressed &quot;Button 02&quot;"/>
            </StackPanel>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <ContentControl x:Name="ContentControlName" Template="{StaticResource ControlTemplateKey}">
            <ContentControl.CommandBindings>
                <CommandBinding Command="Find" Executed="Find_Executed"/>
                <CommandBinding Command="Cut" Executed="Cut_Executed"/>
            </ContentControl.CommandBindings>
        </ContentControl>
    </Grid>
</Window>

代码背后

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace ClickInTemplate
{
    /// <summary>
    /// Логика взаимодействия для ClickWind.xaml
    /// </summary>
    public partial class ClickWind : Window
    {
        public ClickWind()
        {
            InitializeComponent();
        }

        private void Find_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Parameter is ContentControl control)
            {
                // The variable "control" contains the ContentControl that was clicked.
                MessageBox.Show("Command \"Find\" in " + control.Name);
            }
        }

        private void Cut_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Parameter is string text)
            {
                // The variable "control" contains the ContentControl that was clicked.
                MessageBox.Show("Command \"Cut\" with Text=\"" + text + "\"");
            }
        }
    }
}

我使用了已经在 Net 中实现的命令,但是您可以根据需要创建自己的静态实例。

【讨论】:

【解决方案2】:

您通常注册事件处理程序来处理事件。
处理程序的一个参数是发送者对象。在您的情况下,此发件人是引发此事件的 Button 实例。

除了使用EventTrigger之外,基本上有四种方式可以监听一个UI事件(路由事件):

例如在UIElement 内,例如Window:

AddHandler(Button.ClickEvent, new RoutedEventHandler(OnButtonClicked));

// Requires a named element using x:Name e.g. <Button x:Name="Button1" />
this.Button1.AddHandler(Button.ClickEvent, new RoutedEventHandler(OnButtonClicked));
this.Button2.AddHandler(Button.ClickEvent, new RoutedEventHandler(OnButtonClicked));

this.Button1.Click += OnButtonClicked;
this.Button2.Click += OnButtonClicked;

在 XAML 中,您可以将处理程序直接附加到源元素或源元素的任何父 UIElement

<Button x:Name="Button1" 
                Click="OnButtonClicked" />
<Button x:Name="Button2" 
                Click="OnButtonClicked" />

<ContentControl x:Name="ContentControlName" 
                Button.Click="OnButtonClicked" />

最后处理事件。每种监听事件的方式都使用相同的事件处理程序:

private void OnButtonClicked(object sender, RoutedEventArgs e)
{
  // 'sender' parameter references the Button instance,
  // that was actually clicked (Button1 or Button2)
  var clickedButton = sender as Button;
}

或者,您可以将专用的事件处理程序附加到每个 Button,例如 OnButton1ClickedOnButton2Clicked

【讨论】:

  • 谢谢。当没有在资源中设置控制时,事件处理程序可以正常工作。但是,在我的例子中,公共模板是在资源中指定的。如果我询问这个​​或那个按钮的任何属性(例如,button.Content),那么我会收到错误“链接未指向对象。”
  • 这不正常,你必须'做错事。Button 是定义为资源还是在模板中都没有关系。您始终可以设置其属性,例如&lt;Button Click="OnClick" /&gt; 等等。我不知道你在做什么。但这将总是在任何时候都有效。如果它不起作用,我就不会发布这个。
  • 是的,并且为了通过模板实例之一进行访问,我必须执行以下操作:Button button = ContentControlName.Template.FindName("Button1", ContentControlName) as Button; button.AddHandler(Button.ClickEvent, new RoutedEventHandler(OnButtonClicked));
  • 您不需要按钮实例!无需在模板中查找事件源。这些是路由事件。它们向上(冒泡)和向下(隧道)可视化树。旅行时,路线上的每个UIElement 都可以处理它们。您只需像这样注册处理程序:this.AddHandler(Button:ClickEvent, ...)。为了注册路由事件,实例或事件源本身并不重要。您可以简单地将AddHandler(Button.ClickEvent, new RoutedEventHandler(OnButtonClicked)); 添加到您的构造函数中,例如MainWindow。它会起作用的。
  • 您也可以在 XAML 中附加处理程序:&lt;Button Click="OnButtonClicked" /&gt;。这是推荐的解决方案。
猜你喜欢
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-25
  • 2020-11-29
  • 1970-01-01
相关资源
最近更新 更多