I am changing an application that I am developing to MVVM pattern, using Caliburn.Micro Framework.
As I was getting used to this, at first, I was using the IConductor
interface for navigating by inheriting Conductor<object>
at the MainViewModel and then navigating the Screens with the ActivateItem method.
I didn’t use a container, but instead I was instantiating a new ViewModel every single time.
For example, to navigate to FirstViewModel, I was using ActivateItem(new FirstViewModel());
The ViewModelels are light on resources so this implementation wasn’t noticeable. However, I have discovered that the ViewModel instance was not disposed and I have started using Timers to check if the instance is still running, pilling up in the background.
Since then, I am trying all sorts of implementations to control how ViewModels are managed. What I want is to be able to decide whether I reference an already instantiated ViewModel or instantiate a new one. Also, I want to decide whether I dispose the ViewModel or keep it running in order to reconnect to it later.
So, reading the documentation, I have implemented a SimpleContainer in the BootStrapperBase
public class Bootstrapper : BootstrapperBase
{
private SimpleContainer _container = new SimpleContainer();
public Bootstrapper()
{
Initialize();
}
protected override void Configure()
{
_container.Instance(_container);
_container
.Singleton<IWindowManager, WindowManager>()
.Singleton<IEventAggregator, EventAggregator>();
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.ToList()
.ForEach(viewModelType => _container.RegisterPerRequest(viewModelType, viewModelType.ToString(), viewModelType));
}
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
}
I thought that the IoC.Get<FirstViewModel>()
would instantiate a new ViewModel or reuse an open one, if it was already instantiated.
However, it is instantiating a new ViewModel every time.
Also, I cannot figure out how to dispose the ViewModel when activating another one. For example, I have put an OnDeactivate on the FirstViewModel that is triggered when switching to another ViewModel, but I don’t know what code should I put there in order to dispose that instance. I have tried this Setup, implementing IDisposable interface, but I receive a System.StackOverflowException.
protected override void OnDeactivate(bool close)
{
Dispose();
Console.WriteLine("deactivated");
}
public void Dispose()
{
base.TryClose();
}
Isn’t SimpleContainer from Caliburn.Micro enough for managing the ViewModels or should I research on a different approach?
I know that it seems that I am asking multiple questions but all these questions are regarding a main problem which is about managing the viewmodels.
Reading the documentation I came across the Lifecycle
concept which, I think is the concept that would manage my issues but I didn't find further explanation.
The documentation on Caliburn.Micro doesn’t give many examples and I am finding it hard to understand how to use this framework properly without examples.
System.Windows.Forms.Timer
to check if the class was destroyed, but that was keeping it alive – Cosmin