C# winui 3 将事件从组件控件路由到父自定义控件

问题描述 投票:0回答:1

使用 C# winui 3 (.NET 6),我编写了一个自定义控件

CommonButtonControl
,由包含
Button
Image
TextBlock
组成。我的想法是,我可以为应用程序中的所有按钮保持一致的外观和感觉,并简化我的 xaml,因此我只需要添加
CommonButtonControl
以及
ImageSource
Text
Command
的值。

到目前为止一切正常,但我还想添加一个

Click
事件,当组件
CommonButtonControl
事件被触发时,该事件将在
Button Click
上触发。这将增加与标准
Button
控件的一致性,并允许我从
Click
捕获
CommonButtonControl
事件,以执行诸如在执行其他操作之前显示确认对话框之类的操作。

我已在我的

Click
课程中添加了
CommonButtonControl
活动。但是,我在
CommonButtonControl
中定义了
DataDictionary
的 xaml(根据此 documentation),当我尝试捕获组件
Click
Button
事件时,它只会调用位于
DataDictionary
背后的代码 - 不是
CommonButtonControl
类中的代码。似乎没有任何方法可以调用
CommonButtonControl
对象来告诉它组件
Button
事件已触发,以便我可以引发
CommonButtonControl Click
事件。有什么建议么?将
RoutedEventHandler
添加为
DependencyProperty
在概念上似乎不正确。

资源词典

<ResourceDictionary
    x:Class="MyApp.Views.DataTemplatesDictionary"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp.Views">

    <Style TargetType="local:CommonButtonControl" >
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:CommonButtonControl">
                    <Button
                        Command="{x:Bind Command, Mode=OneWay}"
                        Click="Button_Click">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="32"/>
                                <ColumnDefinition Width="auto"/>
                            </Grid.ColumnDefinitions>

                            <Image
                                Grid.Column="0"
                                Width="32"
                                Height="32"
                                Source="{x:Bind ImageSource, Mode=OneWay}"
                                />

                            <TextBlock
                                Margin="8,0,0,0"
                                Grid.Column="1"
                                VerticalAlignment="Center"
                                Text="{x:Bind Text, Mode=OneWay}"
                                Style="{ThemeResource BodyTextBlockStyle}"
                            />
                        </Grid>
                    </Button>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


</ResourceDictionary>

资源字典背后的代码

partial class DataTemplatesDictionary
    {
        public DataTemplatesDictionary()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
        {
            //how to route this to the OnButtonClick method in CommonButtonControl?
        }


    }

CommonButtonControl类

public sealed class CommonButtonControl : Control
    {
        #region members

        private DependencyProperty TextProperty = DependencyProperty.Register(
            nameof(Text),
            typeof(string),
            typeof(CommonButtonControl),
            new PropertyMetadata(default(string)));

        private DependencyProperty ImageSourceProperty = DependencyProperty.Register(
            nameof(ImageSource),
            typeof(ImageSource),
            typeof(CommonButtonControl),
            new PropertyMetadata(default(ImageSource)));

        private DependencyProperty CommandProperty = DependencyProperty.Register(
            nameof(Command),
            typeof(ICommand),
            typeof(CommonButtonControl),
            new PropertyMetadata(null));

        public event RoutedEventHandler Click;

        #endregion

        #region properties

        private void OnButtonClick(object sender, RoutedEventArgs e)
        {
            //how do I call this method when the component button click event is raised?
            Click?.Invoke(this, new());
        }


        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        }

        public ImageSource ImageSource
        {
            get => (ImageSource)GetValue(ImageSourceProperty);
            set => SetValue(ImageSourceProperty, value);
        }

        public ICommand Command
        {
            get => (ICommand)GetValue(CommandProperty);
            set => SetValue(CommandProperty, value);
        }

        #endregion



        public CommonButtonControl()
        {
            this.DefaultStyleKey = typeof(CommonButtonControl);
        }
    }

用法 1 - 通过命令(有效)

           <local:CommonButtonControl 
                Command="{x:Bind _app.DeleteItemCommand}"
                Text="Delete Item"
                ImageSource="{x:Bind _app.DeleteIcon}"
                />

用法 2 - 通过 Click 事件(如何让它工作?)

            <local:CommonButtonControl 
                Click="CommonButtonControl_Click"
                Text="Delete Item"
                ImageSource="{x:Bind _app.DeleteIcon}"
                />
c# custom-controls winui-3
1个回答
0
投票

如果您命名您的

Button
,我们就说“ButtonControl”,

<Style TargetType="local:CustomButton">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:CustomButton">
                <Button x:Name="ButtonControl" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

然后你可以在你的自定义控件类中获取它并订阅ButtonControl

Click
事件:

自定义按钮.cs

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

    public event RoutedEventHandler? Click;

    private Button? ButtonControl { get; set; }

    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        if (ButtonControl is not null)
        {
            ButtonControl.Click -= ButtonControl_Click;
        }

        if (GetTemplateChild(nameof(ButtonControl)) is Button button)
        {
            ButtonControl = button;
            ButtonControl.Click += ButtonControl_Click;
        }
    }

    private void ButtonControl_Click(object sender, RoutedEventArgs e)
    {
        Click?.Invoke(this, e);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.