Xamarin UWP中如何移除EventHandler绑定的委托
问题根因
你当前使用的反射移除事件代码是针对WinForm平台编写的,完全不适用于UWP环境:
- WinForm的控件事件基于
EventHandlerList实现,每个事件对应一个静态字段作为存储key,因此旧方案会尝试获取名为KeyUp的字段、读取控件的Events属性来操作委托列表。 - UWP平台下的
KeyUp是路由事件,不是传统CLR事件,没有对应名称的实例/静态字段存储委托,因此调用GetField("KeyUp")永远返回null。同时UWP控件的事件存储使用内部非公开的EventRegistrationStore结构,和WinForm的EventHandlerList完全无关,后续读取Events属性的逻辑从底层就不成立。
可行实现方案
不建议使用暴力反射移除未知委托,针对Xamarin.Forms UWP平台Entry自定义渲染器的场景,有两种稳定可用的实现思路:
方案1:通过事件Handled标记拦截原有逻辑(推荐)
不需要移除原有绑定的委托,在控件加载完成后注册自定义KeyUp处理逻辑,执行完自定义逻辑后将事件标记为已处理,即可阻断原有委托的执行:
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null) { // 必须等控件Loaded后再注册处理程序,保证执行顺序 Control.Loaded += (sender, routedArgs) => { Control.KeyUp += CustomKeyUpHandler; }; } } private void CustomKeyUpHandler(object sender, KeyRoutedEventArgs e) { // 此处编写自定义的KeyUp处理逻辑 // 标记事件已处理,阻断原有Xamarin绑定的KeyUp委托执行 e.Handled = true; }
注意:路由事件按照注册顺序依次触发,必须在控件Loaded完成后再注册自定义处理程序,才能保证自定义逻辑在原有委托之后执行,Handled标记才能正常截断事件冒泡。
方案2:针对UWP路由事件结构反射移除(不推荐,版本兼容性差)
如果必须完全移除原有绑定的委托,需要针对UWP的事件存储结构编写反射逻辑:
// 注意:该方案依赖UWP和Xamarin.Forms内部私有实现,版本升级后可能失效 protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null) { Control.Loaded += (sender, routedArgs) => { // 获取UIElement内部的事件存储实例 var eventStoreField = typeof(UIElement).GetField("_eventRegistrations", BindingFlags.NonPublic | BindingFlags.Instance); if (eventStoreField == null) return; var eventStore = eventStoreField.GetValue(Control); if (eventStore == null) return; // 查找KeyUp路由事件对应的委托记录 var getEntryMethod = eventStore.GetType().GetMethod("GetEntry", BindingFlags.NonPublic | BindingFlags.Instance); var eventEntry = getEntryMethod?.Invoke(eventStore, new object[] { UIElement.KeyUpEvent }); if (eventEntry == null) return; // 取出所有绑定的委托逐个移除 var handlersField = eventEntry.GetType().GetField("_handlers", BindingFlags.NonPublic | BindingFlags.Instance); if (handlersField?.GetValue(eventEntry) is Delegate[] handlers) { foreach (var handler in handlers) { Control.KeyUp -= (KeyEventHandler)handler; } } }; } }
警告:该方案依赖平台内部非公开的字段、方法实现,不同Windows SDK版本、不同Xamarin.Forms版本的内部字段命名可能发生变化,生产环境谨慎使用。
内容的提问来源于stack exchange,提问作者Kikanye
相关产品推荐
相关产品推荐

