何时在 Xamarin 自定义呈现器中取消挂接事件

Bij*_*ton 1 c# memory-leaks event-handling xamarin xamarin.forms

众所周知,在代码中连接事件处理时,我们冒着将对象留在内存中从而造成内存泄漏的风险。

为了实现一些特殊功能(禁用剪切和复制),我需要在 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;
}
Run Code Online (Sandbox Code Playgroud)

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

我注意到在平台名称空间中IDisposable没有实现VisualElementRenderer<TElement, TNativeElement>UWP但是我无法可靠地证明它被调用了。

更新

按照米查? ?o?nieruk的建议我在检查中添加了 unhooking 以确保OldElement不为空,但是我从未看到任何证据表明它被调用了。

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

当控件从 UI 中移除时,这些渲染器是否应该被清理,从而触发该OnElementChanged方法?

Mic*_*ruk 5

在此处查看有关自定义渲染器的文章:实现视图 它包含自定义渲染器的 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
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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