You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:51:30