0

All:

The more I search for solutions to this question the more confused I become. After spending 12-16 hours watching YouTube, reading StackOverflow and general goggling, I thought I'd plead for additional help.

I would like to create a custom control so I can write various apps to remote to my video switcher.

I've created my control with dependency properties and that part is working well.

This answer on SO seemed to get me close, but I still can't get my app to run. How to wire up a click event for a custom usercontrol button? Should I use CustomControl?

What I simply want to do is click btnIn1 in the control and have it return a "1", btnIn2 returns a "2" and so on.

I've also read about delegates, ICommand, TemplateParts and MVVM patterns which all seem like incredibly complex ways to click a button within a group. Maybe there's just not a simple way to do it.

Here's what I have so far. I simplified everything to a 2x2 matrix switcher (rather than the 4x4 I'm working on)

Thanks for all your help. Norm

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>

Custom Control (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;
        }

    */

}
}
3
  • Can you clarify what it is you want, Norm? Your only ask is that clicking a button return a value, but click handlers return void. What exactly do you want done with the "1" and the "2" because I have no clue from your question. Commented Jul 3, 2017 at 17:04
  • 1
    The button pressed in Matrix44.cs (btnIn1,2,3,.... or btnOut1,2,3...) should send its corresponding number (1,2,3...) back to MainWindow.xaml.cs where it will be stored in the VideoInputChannel or VideoOutputChannel property. Thanks. Commented Jul 3, 2017 at 17:11
  • I don't think you should be calling Click() inside your button click handlers. Seems like that's just an infinite loop. Instead of calling Click, why not do something useful like set the VideoInputChannel and VideoOutputChannel variables? Commented Jul 3, 2017 at 17:37

1 Answer 1

1

You could override the OnApplyTemplate() method to get a reference to each Button and then hook up the event handlers:

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

    }
}

You could then either raise a specific event for each Button or define a custom EventArgs that can be used to identify which Button that was clicked in an event handler:

C# event with custom arguments

Sign up to request clarification or add additional context in comments.

1 Comment

That's a perfect solution! Just what I was looking for, a simple few lines. Thanks so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.