何时取消Xamarin Custom Renderers中的事件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了何时取消Xamarin Custom Renderers中的事件相关的知识,希望对你有一定的参考价值。

众所周知,当在代码中挂起事件处理时,我们冒着将对象留在内存中从而产生内存泄漏的风险。

为了实现一些特殊功能(禁用剪切和复制),我需要在UWP上实现自定义渲染器。虽然禁用剪切和复制与问题并不紧密相关,但我必须连接事件处理程序才能实现此目的。

protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
    base.OnElementChanged(e);

    if (this.Control == null) { return; }

    this.Control.CopyingToClipboard += Control_CopyingToClipboard;
    this.Control.CuttingToClipboard += Control_CuttingToClipboard;
}

private void Control_CuttingToClipboard(TextBox sender, 
                                        TextControlCuttingToClipboardEventArgs args)
{
    args.Handled = true;
}

private void Control_CopyingToClipboard(TextBox sender, 
                                        TextControlCopyingToClipboardEventArgs args)
{
    args.Handled = true;
}

解开这些事件处理程序以防止任何形式泄漏的正确位置是什么?

我注意到在IDisposable平台命名空间中有一个VisualElementRenderer<TElement, TNativeElement>实现而不是UWP但是我无法可靠地证明这个被调用。

更新

根据MichałŻołnieruks的建议,我已经在检查中添加了unhooking,因为OldElement不是null但是我从来没有看到任何证据证明这个被调用。

protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
    base.OnElementChanged(e);

    if (this.Control == null) { return; }

    if (e.OldElement != null)
    {
        System.Debug.WriteLine("I NEVER SEE THIS");

        this.Control.CopyingToClipboard -= Control_CopyingToClipboard;
        this.Control.CuttingToClipboard -= Control_CuttingToClipboard;
    }

    if (e.NewElement != null)
    {
        this.Control.CopyingToClipboard += Control_CopyingToClipboard;
        this.Control.CuttingToClipboard += Control_CuttingToClipboard;
    }
}

如果从UI中删除控件,是否应清理这些渲染器,从而触发OnElementChanged方法?

答案

请在此处查看有关自定义渲染器的文章:Implementing a View它包含自定义渲染器的OnElementChanged方法的模板:

protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)
{
  base.OnElementChanged (e);

  if (Control == null) {
    // Instantiate the native control and assign it to the Control property with
    // the SetNativeControl method
  }

  if (e.OldElement != null) {
    // Unsubscribe from event handlers and cleanup any resources
  }

  if (e.NewElement != null) {
    // Configure the control and subscribe to event handlers
  }
}

因此,当OldElement不为null时,您应取消挂钩事件,并在NewElement存在时挂钩它们。

至于评论中的后续问题(我们是否应该取消订阅,如果上面的第二个没有被触发):我的理解是这两个对象(如此渲染器和本机控制)的生命周期是相同的,在这种情况下没有需要手动取消订阅事件。如果我错了,请纠正我。

以上是关于何时取消Xamarin Custom Renderers中的事件的主要内容,如果未能解决你的问题,请参考以下文章

当动态更改背景时,Xamarin Custom Frame会导致Java.Lang.NullPointerException

MAUI 移植 Xamarin.Forms 自定义渲染器

如何在 xamarin 表单中更改搜索栏取消按钮图像

Xamarin Forms - 在页面打开时填充自定义控件

如何检测何时单击文件输入的取消?

取消/订阅 Xamarin 内容视图中的事件