WPF自定义UserControl多实例使用时路由事件重复注册报错如何解决?
问题根因
- WPF 路由事件是类型级别的静态资源,同一个所有者类型下的同名路由事件全局唯一,仅允许注册一次
- 你将
EventManager.RegisterRoutedEvent的注册逻辑写在了UpDownUc的实例构造函数中,每次创建控件实例都会触发注册操作,第二个实例创建时就会触发重复注册的异常
修复方案
将路由事件的注册逻辑调整为仅在类型初始化时执行一次即可,有两种等效实现方式:
方式1:静态构造函数注册
把注册逻辑放到控件的静态构造函数中,静态构造函数在整个程序生命周期内仅会在类型第一次被加载时执行一次,不会出现重复注册问题,示例代码如下:
public partial class UpDownUc : UserControl { // 声明路由事件静态字段 public static readonly RoutedEvent SettingDecreaseEvent; public static readonly RoutedEvent SettingIncreaseEvent; // 静态构造函数:全局仅执行一次 static UpDownUc() { SettingDecreaseEvent = EventManager.RegisterRoutedEvent( nameof(SettingDecrease), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(UpDownUc)); SettingIncreaseEvent = EventManager.RegisterRoutedEvent( nameof(SettingIncrease), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(UpDownUc)); } // 实例构造函数不需要处理路由事件注册 public UpDownUc() { InitializeComponent(); } // 对外暴露的事件包装器 public event RoutedEventHandler SettingDecrease { add => AddHandler(SettingDecreaseEvent, value); remove => RemoveHandler(SettingDecreaseEvent, value); } public event RoutedEventHandler SettingIncrease { add => AddHandler(SettingIncreaseEvent, value); remove => RemoveHandler(SettingIncreaseEvent, value); } // 按钮点击触发路由事件的逻辑保持不变 private void HandleButtonClick1(object sender, RoutedEventArgs e) { RaiseEvent(new RoutedEventArgs(SettingDecreaseEvent, this)); } private void HandleButtonClick2(object sender, RoutedEventArgs e) { RaiseEvent(new RoutedEventArgs(SettingIncreaseEvent, this)); } }
方式2:声明静态字段时直接注册
直接在声明路由事件静态字段的同时完成注册赋值,效果和静态构造函数一致,代码更简洁:
public partial class UpDownUc : UserControl { // 声明字段同时完成注册,全局仅执行一次 public static readonly RoutedEvent SettingDecreaseEvent = EventManager.RegisterRoutedEvent( nameof(SettingDecrease), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(UpDownUc)); public static readonly RoutedEvent SettingIncreaseEvent = EventManager.RegisterRoutedEvent( nameof(SettingIncrease), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(UpDownUc)); // 其余构造函数、事件包装器、触发逻辑和上面完全一致 public UpDownUc() { InitializeComponent(); } // ... 省略其余重复代码 }
修改完成后即可正常创建任意多的UpDownUc实例,不会再出现重复注册异常。
内容的提问来源于stack exchange,提问作者Hadi Mirzaei
相关产品推荐
相关产品推荐

