EliasMP EliasMP - 11 months ago 89
C# Question

Avoiding Memory Leak. (WeakReference)

This is the scenario:

A XAML with a Entry has a method linked to textchanged´s event.

After encapsulate the UI component(grid in this case) in classes for improving the mantenibility of the code I found the next issue:

I can´t link the method´s event to a specific button on the grid. The problem is I´m calling this method (which has a DisplayActionSheet function which Can´t be call in a simple class. It should be coming from any kind of Page´s class or Application class).

So my first approach was to encapsulate the button in another class.
I created this object(button) in the Page, linked to the method´s event (coded in the page as well. Now I can, is in Page´s class) and pass this object to a new instance of the grid object constructor(another class). Finally I added the grid(with button properly linked into it) to the Page.

Well, I fear this is not really good idea. I am supposing this could be derive in a "Memory Leak Issue" (problem related about deleting object in memory and those have references between different classes what compose them, isn´t?), just creating references between different classes (grid, button and page).

After researching the solution looks like to delegate this method´s event.

But I can´t achieve it, It´s easy (when you know) but the examples are not prepare by my case (or I can´t find it). Could you give a hand? :)

I post the idea of the code, It was implemented over Button inside of a ListView, inside of a grid(a bit more complex, but I want to simplify it).

//This code is called in CarouselPage
// ..............
//ButtonEstadoTarea is type Button
ButtonEstadoTarea bet = new ButtonEstadoTarea();
//OnStartClicked is allocated is this CarouselPage
//
bet.Clicked += this.OnStartClicked;

ListViewIntervencion lvi = new ListViewIntervencion();
lvi.ItemTapped += this.OnItemTapped;
lvi.ItemsSource = intervencion.Interv;

GridCabeceraIntervencion gci = new GridCabeceraIntervencion(intervencion, lvi);
var intervencionContent = new ContentPage
{
Content = gci,
};

this.Children.Add(intervencionContent);

async void OnStartClicked(object sender, EventArgs args)
{
var action = await DisplayActionSheet("Procesar Tarea", null, "Cancel", "Iniciar", "Pausar", "Bloquear", "Terminar");
// MORE MAGIC...
}


Thanks guys.

Answer Source

It is good practice for all mobile platforms(ios, android, xamarin) to use weak reference for storing (page, activity, UIViewcontroller). You can implements reference to page like this:

WeakReference<Page> _pageReference;
public Page Page{
   get {
      Page _page = null;
      _pageReference.TryGetTarget(out _page);
      return _page;
   }
   set{
      _pageReference = new WeakReference<Page>(value);
   }
}

And do not forget ot check for null, when accessing page property. This way you will not have memory leak. To find out more about weak references, please read: https://msdn.microsoft.com/en-us/library/gg712738(v=vs.110).aspx

As a good practice i suggest to use MVVM approach using FreshMvvm, bind button command to model, and display action sheet using CurrentPage parameter