如何在 C# 中 bind/wrap 子控件的事件到自定义控件的事件?

How to bind/wrap an event of a child control to custom control's event, in C#?

我正在构建一个自定义控件(或模板化,如果你介意的话),但我不知道如何将自定义控件内按钮的事件(点击)绑定到自定义控件本身。

我在互联网上搜索过,但有些解决方案仅适用于 WPF(包括 类 在 UWP 平台中不可用),有些适用于 Visual Basic,有些则不完全是我的情况等等在...

这是目前为止运行良好的代码,为了获得最佳许可(请注意,我更改了项目和命名空间的名称以隐藏它,改为 "SomeClass"):

自定义控件,IconButton.cs:

public sealed class IconButton : Control
{
    public IconButton()
    {
        this.DefaultStyleKey = typeof(IconButton);

    }



    public Boolean IconButtonIsLabelVisible
    {
        get { return (Boolean)GetValue(IconButtonIsLabelVisibleProperty); }
        set { SetValue(IconButtonIsLabelVisibleProperty, value); }
    }
    public static readonly DependencyProperty IconButtonIsLabelVisibleProperty =
        DependencyProperty.Register("IconButtonIsLabelVisible", typeof(Boolean), typeof(IconButton), new PropertyMetadata(true));



    public String IconButtonLabel
    {
        get { return (String)GetValue(IconButtonLabelProperty); }
        set { SetValue(IconButtonLabelProperty, value); }
    }
    public static readonly DependencyProperty IconButtonLabelProperty =
        DependencyProperty.Register("IconButtonLabel", typeof(String), typeof(IconButton), new PropertyMetadata("Content"));



    public Double IconButtonLabelMargin
    {
        get { return (Double)GetValue(IconButtonLabelMarginProperty); }
        set { SetValue(IconButtonLabelMarginProperty, value); }
    }
    public static readonly DependencyProperty IconButtonLabelMarginProperty =
        DependencyProperty.Register("IconButtonLabelMargin", typeof(Double), typeof(IconButton), new PropertyMetadata(10));



    public Style IconButtonStyle
    {
        get { return (Style)GetValue(IconButtonStyleProperty); }
        set { SetValue(IconButtonStyleProperty, value); }
    }
    public static readonly DependencyProperty IconButtonStyleProperty =
        DependencyProperty.Register("IconButtonStyle", typeof(Style), typeof(IconButton), new PropertyMetadata(null));



    public IconElement IconButtonIcon
    {
        get { return (IconElement)GetValue(IconButtonIconProperty); }
        set { SetValue(IconButtonIconProperty, value); }
    }
    public static readonly DependencyProperty IconButtonIconProperty =
        DependencyProperty.Register("IconButtonIcon", typeof(IconElement), typeof(IconButton), new PropertyMetadata(0));

}

通用xaml模板文件,Generic.xaml:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SomeClass.Controls">

<Style TargetType="local:IconButton">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:IconButton">
                <Button x:Name="ClickButton" Style="{TemplateBinding IconButtonStyle}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}">
                    <Grid Margin="{TemplateBinding Padding}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>

                        <ContentPresenter x:Name="Content"
                                Content="{TemplateBinding IconButtonIcon}"
                                Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center"/>

                        <Grid Grid.Column="1" Width="{TemplateBinding IconButtonLabelMargin}"/>

                        <TextBlock Grid.Column="2" Text="{TemplateBinding IconButtonLabel}" Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center"/>
                    </Grid>
                </Button>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

还有 MainPage.xaml,我想在其中使用 IconButton:

<Page
x:Class="SomeClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SomeClass"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:testControls="using:SomeClass.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Grid>
    <testControls:IconButton x:Name="TestButton" Click"?" IconButtonLabelMargin="5" HorizontalAlignment="Center" Foreground="Aqua" VerticalAlignment="Center" Background="Transparent" >
        <testControls:IconButton.IconButtonIcon>
            <SymbolIcon Symbol="Preview"/>
        </testControls:IconButton.IconButtonIcon>
    </testControls:IconButton>
</Grid>

So, given this code, I would like to bind in some way the Click event of the ClickButton in the xaml template of the IconButton to the default Click event of the IconButton control itself, so that it can be easily used in the mainpage by simply specifying the Click event.

谢谢你的好意和关注。

此致。

这样做需要重写控件中的 OnApplyTemplate 方法,在控件中找到命名模板部分,并在包装​​器上引发事件。

在您的自定义控件中:

ButtonBase clickButtonPart = null;
public const string ClickButtonTemplatePartName = "ClickButton";
public event EventHandler Click;

protected override void OnApplyTemplate()
{
  // In case the template changes, you want to stop listening to the
  // old button's Click event.
  if (clickButtonPart != null)
  {
    clickButtonPart.Click -= ClickForwarder;
    clickButtonPart = null;
  }

  // Find the template child with the special name. It can be any kind
  // of ButtonBase in this example.
  clickButtonPart = GetTemplateChild(ClickButtonTemplatePartName) as ButtonBase;

  // Add a handler to its Click event that simply forwards it on to our
  // Click event.
  if (clickButtonPart != null)
  {
    clickButtonPart.Click += ClickForwarder;
  }
}

private void ClickForwarder(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
  Click?.Invoke(this, null);
}