一文带你了解WPF中的附加事件
黑夜中的潜行者 人气:0什么是附加事件
Microsoft 官方概述:
附加事件可用于在非元素类中定义新的 路由事件 ,并在树中的任何元素上引发该事件。 为此,必须将附加事件注册为路由事件,并提供支持附加事件功能的特定 支持代码 。 由于附加事件注册为路由事件,因此在元素树中引发时,它们会传播到元素树中。
简单来说就是,可以进行附加操作的事件,必须为路由事件(RoutedEvent)。
附加事件用法
在 XAML 语法中,附加事件由其 事件名称和所有者 类型指定,格式为 <owner type>.<event name>。 由于事件名称使用其所有者类型的名称进行限定,因此语法允许事件附加到任何可以实例化的元素。 此语法也适用于附加到事件路由中任意元素的常规路由事件的处理程序。
Microsoft 官方文档
这里简略的借用文档中的说明,详细学习请以文档为准:附加事件概述 (WPF .NET)
附加事件案例
定义自定义控件
using System.Windows; using System.Windows.Controls; namespace assembly { /// <summary> /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。 /// /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。 /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 /// 元素中: /// /// xmlns:MyNamespace="clr-namespace:assembly" /// /// /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。 /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 /// 元素中: /// /// xmlns:MyNamespace="clr-namespace:assembly;assembly=assembly" /// /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用, /// 并重新生成以避免编译错误: /// /// 在解决方案资源管理器中右击目标项目,然后依次单击 /// “添加引用”->“项目”->[浏览查找并选择此项目] /// /// /// 步骤 2) /// 继续操作并在 XAML 文件中使用控件。 /// /// <MyNamespace:MessagePopup/> /// /// </summary> public class MessagePopup : UserControl { public static readonly DependencyProperty BusinessTypeProperty = DependencyProperty.Register(nameof(BusinessType), typeof(string), typeof(MessagePopup), new PropertyMetadata(string.Empty)); /// <summary> /// 业务类型 /// </summary> public string BusinessType { get { return (string)GetValue(BusinessTypeProperty); } set { SetValue(BusinessTypeProperty, value); } } public static readonly DependencyProperty SecondsProperty = DependencyProperty.Register(nameof(Seconds), typeof(string), typeof(MessagePopup), new PropertyMetadata(string.Empty)); /// <summary> /// 秒数 /// </summary> public string Seconds { get { return (string)GetValue(SecondsProperty); } set { SetValue(SecondsProperty, value); } } static MessagePopup() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MessagePopup), new FrameworkPropertyMetadata(typeof(MessagePopup))); } } }
自定义控件样式
下面的样式使用 ControlTemplate 自定义的控件样式,其中的 Button 按钮是不能进行事件绑定的,当然命令绑定也是不行的。
<Application x:Class="assembly.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:assembly" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <!--#region--> <Style x:Key="popup" TargetType="{x:Type local:MessagePopup}"> <Setter Property="Height" Value="436" /> <Setter Property="Width" Value="840" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:MessagePopup}"> <Grid> <Grid.Background> <ImageBrush ImageSource="pack://application:,,,/images/bg-Tips.png" /> </Grid.Background> <Grid.RowDefinitions> <RowDefinition Height="0.7*" /> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Grid Grid.Row="0" Margin="55,0"> <Grid.RowDefinitions> <RowDefinition Height="0.5*" /> <RowDefinition /> </Grid.RowDefinitions> <Button Width="100" Height="40" Margin="0,20,0,0" HorizontalAlignment="Right" Tag="0"> <Button.Template> <ControlTemplate> <StackPanel VerticalAlignment="Center" Orientation="Horizontal"> <Image Source="pack://application:,,,/images/ico-close.png" /> <TextBlock Margin="5,0,0,0" VerticalAlignment="Center" FontSize="28" FontWeight="Black" Foreground="#7582CC" Text="关闭" /> </StackPanel> </ControlTemplate> </Button.Template> </Button> <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal"> <TextBlock FontSize="42" FontWeight="Black" Text="" /> <TextBlock FontSize="42" FontWeight="Black" Foreground="#F95A00" Text="{TemplateBinding BusinessType}" /> <TextBlock FontSize="42" FontWeight="Black" Text="" /> </StackPanel> </Grid> <Line Grid.Row="1" Margin="80,0" Stroke="#8DB2BD" StrokeDashArray="2,2" StrokeThickness="4" X1="0" X2="650" /> <Grid Grid.Row="2" Margin="55,0"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Grid Grid.Row="0" Margin="75,0"> <StackPanel Margin="0,30,0,0" VerticalAlignment="Center" Orientation="Horizontal"> <TextBlock VerticalAlignment="Center" FontSize="32" Foreground="#002C86" Text="" /> <Image Height="40" Margin="20,0" Source="pack://application:,,,/images/ico-arrow.png" /> <Button Width="180" Height="50" Tag="1"> <Button.Template> <ControlTemplate> <Border Background="#DDE2FF" CornerRadius="5"> <StackPanel Height="40" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal"> <Image Source="pack://application:,,,/images/ico-filer.png" /> <TextBlock Margin="5,0,0,0" VerticalAlignment="Center" FontSize="28" FontWeight="Black" Foreground="#7582CC" Text="跳转页面" /> </StackPanel> </Border> </ControlTemplate> </Button.Template> </Button> </StackPanel> </Grid> <Grid Grid.Row="1"> <StackPanel Margin="0,20,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal"> <TextBlock FontSize="38" Foreground="#FFD873" Text="{TemplateBinding Seconds}" /> <TextBlock FontSize="38" Foreground="#FFD873" Text="" /> <TextBlock Margin="10,0,0,0" VerticalAlignment="Bottom" FontSize="32" Foreground="#FFFFFF" Text="" /> </StackPanel> </Grid> </Grid> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--#endregion--> </ResourceDictionary> </Application.Resources> </Application>
效果
注册使用附加事件
使用该自定义控件时,为其注册 Button.Click 事件,属于原生路由事件。对应其用方法可以得出,该事件触发的是 Button 元素的 Click 事件。
简单来说就是,只有自定义控件中的 Button 元素才能触发当前的 Click 事件。(附加事件用法)
<Window x:Class="assembly.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:comm="clr-namespace:assembly" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="MainWindow" Width="900" Height="550" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> <Grid> <comm:MessagePopup x:Name="popup" Width="840" Height="436" Button.Click="popup_Click" Style="{StaticResource popup}" Visibility="Visible" /> </Grid> </Window>
元素树中声明了两个 Buuton 这里暂且通过 Button 的 Tag 值来区分,不仅限于 Tag。
private void popup_Click(object sender, RoutedEventArgs e) { string tag = (string)((FrameworkElement)e.OriginalSource).Tag; if (tag == "0") { MessageBox.Show("是关闭按钮"); //CloseTimer(); } else if (tag == "1") { MessageBox.Show("是跳转按钮"); } }
效果
加载全部内容