使用 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}"
/>
如果您命名您的
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);
}
}