【问题标题】:Add separate click events for multiple buttons in custom control为自定义控件中的多个按钮添加单独的单击事件
【发布时间】:2017-07-03 16:55:39
【问题描述】:

全部:

我越是寻找这个问题的解决方案,我就越感到困惑。在花了 12 到 16 个小时观看 YouTube、阅读 StackOverflow 和一般的护目镜之后,我想我应该请求更多帮助。

我想创建一个自定义控件,以便我可以编写各种应用程序来远程连接到我的视频切换器。

我已经使用依赖属性创建了我的控件,并且该部分运行良好。

这个关于 SO 的答案似乎让我很接近,但我仍然无法让我的应用程序运行。 How to wire up a click event for a custom usercontrol button? Should I use CustomControl?

我只想做的是单击控件中的 btnIn1 并让它返回一个“1”,btnIn2 返回一个“2”等等。

我还阅读了有关委托、ICommand、TemplateParts 和 MVVM 模式的内容,这些似乎都是单击组内按钮的极其复杂的方法。也许没有一个简单的方法来做到这一点。

这是我目前所拥有的。我将所有东西都简化为 2x2 矩阵切换器(而不是我正在研究的 4x4)

感谢您的所有帮助。 规范

Generic.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VideoSwitcher"
xmlns:enk="clr-namespace:VideoSwitcher.Controls">

<Style TargetType="{x:Type enk:Matrix44}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type enk:Matrix44}">
                <Grid x:Name="grdBase" HorizontalAlignment="Stretch">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="25*"/>
                        <ColumnDefinition Width="25*"/>
                        <ColumnDefinition Width="25*"/>
                        <ColumnDefinition Width="25*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="40*"/>
                        <RowDefinition Height="100*"/>
                        <RowDefinition Height="40*"/>
                        <RowDefinition Height="100*"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Label x:Name="lblInputHeader" Content="Input"
                           Grid.Column="0"
                           Grid.Row="0"
                           Grid.ColumnSpan="4"
                           Visibility="{TemplateBinding HeaderVisible}"
                           FontFamily="{TemplateBinding HeaderFont}"
                           FontSize="{TemplateBinding HeaderFontSize}"/>
                    <StackPanel Orientation="Horizontal"
                                Grid.Column="0"
                                Grid.Row="1"
                                Grid.ColumnSpan="4">
                        <Button x:Name="btnIn1"
                                Margin="{TemplateBinding ButtonMargin}"
                                Height="{TemplateBinding ButtonHeight}"
                                Width="{TemplateBinding ButtonWidth}"
                                Content="{TemplateBinding Input1Label}"
                                Click="btnIn1Click"/>
                        <Button x:Name="btnIn2"
                                Margin="{TemplateBinding ButtonMargin}"
                                Height="{TemplateBinding ButtonHeight}"
                                Width="{TemplateBinding ButtonWidth}"
                                Content="{TemplateBinding Input2Label}"
                                Click="btnIn2Click"/>
                    </StackPanel>
                    <Label x:Name="lblOutputHeader" Content="Output"
                           Grid.Column="0"
                           Grid.Row="2"
                           Grid.ColumnSpan="4"
                           Visibility="{TemplateBinding HeaderVisible}"
                           FontFamily="{TemplateBinding HeaderFont}"
                           FontSize="{TemplateBinding HeaderFontSize}"/>
                    <StackPanel Orientation="Horizontal"
                                Grid.Column="0"
                                Grid.Row="3"
                                Grid.ColumnSpan="4">
                        <Button x:Name="btnOut1"
                                Margin="{TemplateBinding ButtonMargin}"
                                Height="{TemplateBinding ButtonHeight}"
                                Width="{TemplateBinding ButtonWidth}"
                                Content="{TemplateBinding Output1Label}"
                                Click="btnOut1Click"/>
                        <Button x:Name="btnOut2"
                                Margin="{TemplateBinding ButtonMargin}"
                                Height="{TemplateBinding ButtonHeight}"
                                Width="{TemplateBinding ButtonWidth}"
                                Content="{TemplateBinding Output2Label}"
                                Click="btnOut2Click"/>
                    </StackPanel>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
</ResourceDictionary>

自定义控件 (Matrix44.cs)

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.ComponentModel;

namespace VideoSwitcher.Controls
{

public class Matrix44 : Control
{

    #region Events - Go here if I can ever find out how to use them


    #endregion

    //This does not work --------
    public event RoutedEventHandler Click;

    void btnIn1Click(object sender, RoutedEventArgs e)
    {
        if (this.Click != null)
        {
            this.Click(this, e);
        }
    }

    void btnIn2Click(object sender, RoutedEventArgs e)
    {
        if (this.Click != null)
        {
            this.Click(this, e);
        }
    }

    void btnOut1Click(object sender, RoutedEventArgs e)
    {
        if (this.Click != null)
        {
            this.Click(this, e);
        }
    }

    void btnOut2Click(object sender, RoutedEventArgs e)
    {
        if (this.Click != null)
        {
            this.Click(this, e);
        }
    }

    #region Properties - Exposed to the user in the Properties panel, XAML or code-behind

    #region Switcher Appearance Properies (Height, Width, Margin)

    [Category("Switcher Appearance Properties")]
    public double ButtonHeight
    {
        get { return (double)GetValue(ButtonHeightProperty); }
        set { SetValue(ButtonHeightProperty, value); }
    }

    public static readonly DependencyProperty ButtonHeightProperty =
        DependencyProperty.Register(nameof(ButtonHeight), typeof(double), typeof(Matrix44), new PropertyMetadata(50.0));

    [Category("Switcher Appearance Properties")]
    public double ButtonWidth
    {
        get { return (double)GetValue(ButtonWidthProperty); }
        set { SetValue(ButtonWidthProperty, value); }
    }

    public static readonly DependencyProperty ButtonWidthProperty =
        DependencyProperty.Register(nameof(ButtonWidth), typeof(double), typeof(Matrix44), new PropertyMetadata(50.0));

    [Category("Switcher Appearance Properties")]
    public Thickness ButtonMargin
    {
        get { return (Thickness)GetValue(ButtonMarginProperty); }
        set { SetValue(ButtonMarginProperty, value); }
    }

    public static readonly DependencyProperty ButtonMarginProperty =
        DependencyProperty.Register("ButtonMargin", typeof(Thickness), typeof(Matrix44));



    #endregion

    #region Labels

    [Category("Switcher Label Properties")]
    public string Input1Label
    {
        get { return (string)GetValue(Input1LabelProperty); }
        set { SetValue(Input1LabelProperty, value); }
    }


    public static readonly DependencyProperty Input1LabelProperty =
        DependencyProperty.Register(nameof(Input1Label), typeof(string), typeof(Matrix44), new PropertyMetadata("Input 1"));

    [Category("Switcher Label Properties")]
    public string Input2Label
    {
        get { return (string)GetValue(Input2LabelProperty); }
        set { SetValue(Input2LabelProperty, value); }
    }

    public static readonly DependencyProperty Input2LabelProperty =
        DependencyProperty.Register(nameof(Input2Label), typeof(string), typeof(Matrix44), new PropertyMetadata("Input 2"));


    [Category("Switcher Label Properties")]
    public string Output1Label
    {
        get { return (string)GetValue(Output1LabelProperty); }
        set { SetValue(Output1LabelProperty, value); }
    }

    public static readonly DependencyProperty Output1LabelProperty =
        DependencyProperty.Register(nameof(Output1Label), typeof(string), typeof(Matrix44), new PropertyMetadata("Output 1"));

    [Category("Switcher Label Properties")]
    public string Output2Label
    {
        get { return (string)GetValue(Output2LabelProperty); }
        set { SetValue(Output2LabelProperty, value); }
    }

    public static readonly DependencyProperty Output2LabelProperty =
        DependencyProperty.Register(nameof(Output2Label), typeof(string), typeof(Matrix44), new PropertyMetadata("Output 2"));

    #endregion

    #region Header Properties

    [Category("Switcher Header Properties")]
    public Visibility HeaderVisible
    {
        get { return (Visibility)GetValue(HeaderVisibleProperty); }
        set { SetValue(HeaderVisibleProperty, value); }
    }

    public static readonly DependencyProperty HeaderVisibleProperty =
        DependencyProperty.Register("HeaderVisible", typeof(Visibility), typeof(Matrix44));

    [Category("Switcher Header Properties")]
    public FontFamily HeaderFont
    {
        get { return (FontFamily)GetValue(HeaderFontProperty); }
        set { SetValue(HeaderFontProperty, value); }
    }

    public static readonly DependencyProperty HeaderFontProperty =
        DependencyProperty.Register("HeaderFont", typeof(FontFamily), typeof(Matrix44));

    [Category("Switcher Header Properties")]
    public double HeaderFontSize
    {
        get { return (double)GetValue(HeaderFontSizeProperty); }
        set { SetValue(HeaderFontSizeProperty, value); }
    }

    public static readonly DependencyProperty HeaderFontSizeProperty =
        DependencyProperty.Register("HeaderFontSize", typeof(double), typeof(Matrix44));


    #endregion

    #region Channel Properties
    [Category("Switcher Channel Properties")]

    //Channel Property - use to extend switcher tool capabilties; e.g. add new bank of ins/outs and remap input 1 to input 5 on 2nd bank

    public int Input1Channel
    {
        get { return (int)GetValue(Input1ChannelProperty); }
        set { SetValue(Input1ChannelProperty, value); }
    }

    public static readonly DependencyProperty Input1ChannelProperty =
        DependencyProperty.Register("Input1Channel", typeof(int), typeof(Matrix44), new PropertyMetadata(1));

    [Category("Switcher Channel Properties")]
    public bool Input1Enabled
    {
        get { return (bool)GetValue(Input1EnabledProperty); }
        set { SetValue(Input1EnabledProperty, value); }
    }

    public static readonly DependencyProperty Input1EnabledProperty =
        DependencyProperty.Register("Input1Enabled", typeof(bool), typeof(Matrix44), new PropertyMetadata(false));


    [Category("Switcher Channel Properties")]
    public int Input2Channel
    {
        get { return (int)GetValue(Input2ChannelProperty); }
        set { SetValue(Input2ChannelProperty, value); }
    }

    public static readonly DependencyProperty Input2ChannelProperty =
        DependencyProperty.Register("Input2Channel", typeof(int), typeof(Matrix44), new PropertyMetadata(2));

    [Category("Switcher Channel Properties")]
    public bool Input2Enabled
    {
        get { return (bool)GetValue(Input1EnabledProperty); }
        set { SetValue(Input1EnabledProperty, value); }
    }

    [Category("Switcher Channel Properties")]
    public int Output1Channel
    {
        get { return (int)GetValue(Output1ChannelProperty); }
        set { SetValue(Output1ChannelProperty, value); }
    }

    //Output channels

    public static readonly DependencyProperty Output1ChannelProperty =
        DependencyProperty.Register("Output1Channel", typeof(int), typeof(Matrix44), new PropertyMetadata(1));

    [Category("Switcher Channel Properties")]
    public int Output2Channel
    {
        get { return (int)GetValue(Output2ChannelProperty); }
        set { SetValue(Output2ChannelProperty, value); }
    }

    public static readonly DependencyProperty Output2ChannelProperty =
        DependencyProperty.Register("Output2Channel", typeof(int), typeof(Matrix44), new PropertyMetadata(2));

    #endregion

    #endregion

    public Matrix44()
    {
        DefaultStyleKey = typeof(Matrix44);
    }

}

}

MainWindow.XAML

<Window
    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:VideoSwitcher"
    xmlns:Controls="clr-namespace:VideoSwitcher.Controls" x:Class="VideoSwitcher.MainWindow"
    mc:Ignorable="d"
    Title="MainWindow" Height="300" Width="200">
<Grid Margin="0,1,0,0">
    <Controls:Matrix44 x:Name="swtMatrix"
                       HorizontalAlignment="Left"
                       Margin="10,10,0,0"
                       VerticalAlignment="Top"
                       ButtonHeight="65"
                       ButtonMargin="4"
                       ButtonWidth="65"/>
    <Button x:Name="btnTake"
            Content="Take"
            HorizontalAlignment="Left"
            Margin="10,213,0,0"
            VerticalAlignment="Top"
            Width="146"
            Height="45" Click="btnTake_Click"/>
</Grid>

MainWindow.xaml.cs

    using System.Windows;

    namespace VideoSwitcher
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public int VideoInputChannel { get; set; }
    public int VideoOutputChannel { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        AddLabelsToMatrix();
    }

    public void AddLabelsToMatrix()
    {
        swtMatrix.Input1Label = "DVR1";
        swtMatrix.Input2Label = "DVR2";
        swtMatrix.Output1Label = "Videowall";
        swtMatrix.Output2Label = "US Right";
    }

    private void btnTake_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Input channel: " + VideoInputChannel + " routed to Output: " + VideoOutputChannel);
    }


    /* switcher button psuedo-code

        btnIn1_Click (object sender, RoutedEventArgs e)
        {
            //get input channel of matrix switcher
            VideoInputChannel = swtMatrix.btnIn1.Channel;
        }

        btnIn2_Click (object sender, RoutedEventArgs e)
        {
            //get input channel of matrix switcher
            VideoInputChannel = swtMatrix.btnIn2.Channel;
        }

         btnOut1_Click (object sender, RoutedEventArgs e)
        {
            //get output channel of matrix switcher
            VideoInputChannel = swtMatrix.btnIn1.Channel;
        }

        btnOut2_Click (object sender, RoutedEventArgs e)
        {
            //get output channel of matrix switcher
            VideoInputChannel = swtMatrix.btnIn2.Channel;
        }

    */

}
}

【问题讨论】:

  • 你能说清楚你想要什么吗,Norm?您唯一的要求是单击按钮返回一个值,但单击处理程序返回 void。你到底想用“1”和“2”做什么,因为我不知道你的问题。
  • Matrix44.cs 中按下的按钮(btnIn1,2,3,.... 或 btnOut1,2,3...)应该发送其对应的数字(1,2,3... ) 返回到 MainWindow.xaml.cs,它将存储在 VideoInputChannel 或 VideoOutputChannel 属性中。谢谢。
  • 我认为您不应该在按钮单击处理程序中调用 Click()。似乎这只是一个无限循环。与其调用 Click,不如做一些有用的事情,比如设置 VideoInputChannel 和 VideoOutputChannel 变量?

标签: c# wpf xaml


【解决方案1】:

您可以重写 OnApplyTemplate() 方法以获取对每个 Button 的引用,然后连接事件处理程序:

public class Matrix44 : Control
{
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        Button btnOut1 = this.Template.FindName("btnOut1", this) as Button;
        if (btnOut1 != null)
            btnOut1.Click += btnIn1Click;

        //...and so on for each Button

    }
}

然后,您可以为每个 Button 引发特定事件,或者定义一个自定义 EventArgs,用于识别在事件处理程序中单击了哪个 Button

C# event with custom arguments

【讨论】:

  • 这是一个完美的解决方案!正是我想要的,简单的几行。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2022-01-14
  • 2012-10-02
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2018-05-16
相关资源
最近更新 更多