I have long living models with properties displayed using a view. The DataContext on my view is a ViewModel with a short lifespan.
Examples include row viewmodels in lists.
To avoid memory leaks the viewmodels subscribe to models using System.Windows.WeakEventManager
.
If I were to subscribe normally the long living model would keep the viewmodel alive.
Using the WeakEventManager in about every viewmodel seems very cumbersome. The usecase looks like a standard usecase for WPF. Am I missing a fundamental concept of WPF or C# that would help me writing better code here?
Here is a minimal Example that Illustrates what I do right now.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//building would take place in a factory method
DataContext = new ShortLivedViewModel(new LongLivingModel());
}
}
public class ShortLivedViewModel : INotifyPropertyChanged
{
private string _myText;
public ShortLivedViewModel(LongLivingModel model)
{
model.SomeEvent += SomeEventHandler;
WeakEventManager<LongLivingModel, EventArgs>.AddHandler(model, nameof(LongLivingModel.SomeEvent),
SomeEventHandler);
}
public string MyText
{
get => _myText;
set
{
_myText = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MyText)));
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void SomeEventHandler(object sender, EventArgs e)
{
//The actual update content would come from the event args
MyText = Guid.NewGuid().ToString("N");
}
}
public class LongLivingModel
{
//the event does not matter too much so I omit the implementation that causes it
public EventHandler<EventArgs> SomeEvent = delegate { };
}
My question is if there is a less cumbersome way of subscribing to a long living object from a short living object. Or if there is some facility in WPF that I am missing for this.
It strikes me that this would be the standard case.
What I played around with is adding an IDisposable
interface but that just leaves me with tacking when to call dispose so I can unsubscribe.
What I am looking for may be a combination of telling the GC that subscriptions do not count for the lifetime of the viewmodel and unsubscribing on destruction - or an even better solution.
I think the parent viewmodel should be responsbile for getting rid of references.
This is a simple example that pushes an update to each child viewmodel. When a child needs to be cleaned up, it tells the parent to remove its reference.