如果是RoutedEvent,
先声明RouteEvent 指明RouteHandler名字和参数类型,
再定义事件包装器,说明处理的是RouteEvent,
自定义事件参数,需要传入事件,和调用该事件的element
或者逆向记忆
触发事件要传事件参数吧,你怎么知道这个参数传给谁,EventArgs里就要有
cs
/// <summary>
/// 自定义路由事件
/// </summary>
public class TimeButton:Button
{
/// <summary>
/// 声明和注册路由事件
/// </summary>
public static readonly RoutedEvent TimeEvent = EventManager.RegisterRoutedEvent("Time",//需要与包装器一致
RoutingStrategy.Bubble,
typeof(EventHandler<TimeEventArgs>), // 事件处理器类型
typeof(TimeButton));
/// <summary>
/// 事件包装器
/// </summary>
public event RoutedEventHandler Time{
add { this.AddHandler(TimeEvent, value); }
remove
{
this.RemoveHandler(TimeEvent, value);
}
}
/// <summary>
/// 重写方法,激发事件
/// </summary>
protected override void OnClick()
{
base.OnClick();
TimeEventArgs e = new TimeEventArgs(TimeEvent,this);
e.ClickTime = DateTime.Now;
this.RaiseEvent(e);
}
}
public class TimeEventArgs : RoutedEventArgs {
public TimeEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) {
}
public DateTime ClickTime { get; set; }
}
<local:TimeButton x:Name="timeButton1" Content="报时" Time="timeButton1_Time"></local:TimeButton>
private void timeButton1_Time(object sender, TimeEventArgs e)
{
this.txtInfo.AppendText(string.Format("当前响应事件对象:{0},响应事件时间为:{1}\r\n", (sender as FrameworkElement).Name, e.ClickTime.ToString("yyyy-MM-dd hh:mm:ss.fff")));
}
RoutedPropertyChangedEvent(属性变化的路由事件)
通常与自定义依赖属性相结合
1. 确定泛型类型
RoutedPropertyChangedEvent 本质是针对特定类型属性变化的事件,需要指定泛型参数 T(例如 int、string、Color 等)。
2. 声明路由事件标识符
使用 EventManager.RegisterRoutedEvent 注册事件,事件处理器类型指定为 RoutedPropertyChangedEventHandler<T>(框架已定义的泛型委托)。
cs
public class MyCustomControl : Control
{
// 1. 声明路由事件标识符(静态只读)
public static readonly RoutedEvent ValueChangedEvent =
EventManager.RegisterRoutedEvent(
"ValueChanged", // 事件名称
RoutingStrategy.Bubble, // 路由策略(冒泡/隧道)
typeof(RoutedPropertyChangedEventHandler<int>), // 处理器类型(泛型为属性类型)
typeof(MyCustomControl)); // 所属控件类型
}
3. 定义事件包装器
通过 add/remove 访问器包装,供外部订阅:
cs
public class MyCustomControl : Control
{
// 2. 事件包装器(名称与注册的事件名称一致)
public event RoutedPropertyChangedEventHandler<int> ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
}
4. 定义依赖属性
(通常与属性变化事件配套)
属性变化事件通常与依赖属性配合使用,当属性值变化时自动触发事件:
cs
public class MyCustomControl : Control
{
// 3. 定义依赖属性(属性变化的源头)
public int MyValue
{
get { return (int)GetValue(MyValueProperty); }
set { SetValue(MyValueProperty, value); }
}
// 依赖属性标识符
public static readonly DependencyProperty MyValueProperty =
DependencyProperty.Register(
"MyValue", // 属性名称
typeof(int), // 属性类型
typeof(MyCustomControl), // 所属类型
new PropertyMetadata(0, OnMyValueChanged)); // 默认值和变化回调
// 4. 属性变化回调(触发事件的地方)
private static void OnMyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyCustomControl control = (MyCustomControl)d;
int oldValue = (int)e.OldValue; // 旧值
int newValue = (int)e.NewValue; // 新值
// 触发路由事件,传递旧值和新值
control.RaiseEvent(new RoutedPropertyChangedEventArgs<int>(oldValue, newValue, ValueChangedEvent));
}
}
5. 使用自定义的 RoutedPropertyChangedEvent
外部可以像订阅普通事件一样使用,并且能获取属性变化的旧值和新值:
cs
<!-- XAML中使用 -->
<local:MyCustomControl MyValue="5" ValueChanged="MyControl_ValueChanged" />
// 后台代码处理事件
private void MyControl_ValueChanged(object sender, RoutedPropertyChangedEventArgs<int> e)
{
Console.WriteLine($"属性值变化:从 {e.OldValue} 变为 {e.NewValue}");
// 可通过 e.Handled = true 阻止事件继续传播
}
这种模式在 WPF 控件中非常常见,例如 Slider 的 ValueChanged、TextBox 的 TextChanged 等事件都是基于此实现的。