Home > Mobile >  Xamarin Forms : disposed object problem with an Android renderer
Xamarin Forms : disposed object problem with an Android renderer

Time:01-03

Using an Android renderer for a Frame inside a page in Xamarin Forms, I need to change the position of this object after the size allocation of the page. The page being in a tab in a Shell, when I change tabs and I come back I get the exception 'Cannot access a disposed object' in the renderer.

The exception occurs on this line of UpdatePos:

SetY(20);

My problem has been reproduced with the code below :

The page :

public partial class TestPage : ContentPage
{
    public partial class Container : Frame
    {
        public delegate void PosChangedEvent();
        public event PosChangedEvent HandlerPosUpdated;
        public void Update()
        {
            HandlerPosUpdated?.Invoke();
        }
    }
    Container _container = null;
    public TestPage()
    {
        InitializeComponent();
        _container = new Container()
        {
            Content = new myView()
        };
        main_layout.Children.Add(_container); 
    }
    protected override void OnSizeAllocated(double width, double height)
    {
        base.OnSizeAllocated(width, height);
        _container.Update();
    }
}

The renderer :

public class ContainerRenderer : ViewRenderer<Frame, Android.Views.View>
{
    public ContainerRenderer(Context context) : base(context)
    {}
    public void UpdatePos()
    {
        SetY(20); // System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'ContainerRenderer'.'

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

        if (e.NewElement != null)
        {
            TestPage.Container view = e.NewElement as TestPage.Container;
            if (view != null)
            {
                view.HandlerPosUpdated  = UpdatePos;
            }
        }
        if (e.OldElement != null)
        {
            TestPage.Container view = e.OldElement as TestPage.Container;
            if (view != null)
            {
                view.HandlerPosUpdated -= UpdatePos;
            }
        }
    }
}

How this exception could be avoided ?

Any hints are welcome!

CodePudding user response:

Remove that handler when the custom renderer is disposed:

private bool disposedValue;

protected override void Dispose(bool disposing)
{
    if (!disposedValue)
    {
        if (disposing)
        {
            RemoveHandlerPosUpdated();
        }

        disposedValue = true;
    }

    base.Dispose(disposing);
}

private void RemoveHandlerPosUpdated()
{
    if (Element != null)
    {
        TestPage.Container view = Element as TestPage.Container;
        if (view != null)
        {
            view.HandlerPosUpdated -= UpdatePos;
        }
    }

}

If that doesn't fix it, then may need to do something in TestPage.Container class, to remove any handlers attached to HandlerPosUpdated. Details TBD.

  • Related