Reputation: 61
My ViewModel instantiate resource that must be released when the program exits.
public class MainViewModel : ViewModelBase
{
LocalServer Server { get; set; }
Resource MyResorce { get; set; }
public MainViewModel(LocalServer server)
{
this.Server = server;
MyResource = new Resource();
}
public override void Cleanup()
{
if (MyResource != null)
MyResource.Close();
MyResource = null;
base.Cleanup();
}
}
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel MainVM
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public static void Cleanup()
{
// Wrong!! The collection is empty!
foreach (ViewModelBase vm in ServiceLocator.Current.GetAllInstances<ViewModelBase>() )
vm.Cleanup();
SimpleIoc.Default.Unregister<MainViewModel>();
Messenger.Reset();
}
}
But I noticed that ServiceLocator.Current.GetAllInstances<MainViewModel>()
, returns all instances of a given ViewModel but if I ask ServiceLocator.Current.GetAllInstances<ViewModelBase>()
like in this example it returns an empty collection!!
So, it's possible call CleanUp() for all my ViewModel using only one foreach?
Many thanks.
Upvotes: 6
Views: 6718
Reputation: 7005
You won't be able to do this in one go. Here's why:
Internally, the SimpleIoc object contains a dictionary of instances:
Dictionary<Type, Dictionary<string, object>> _instancesReDictionary<Type, Dictionary<string, object>> _instancesRegistrygistry
When you call GetAllInstances what's actually happening under the hood is:
public IEnumerable<TService> GetAllInstances<TService>()
{
var serviceType = typeof(TService);
return GetAllInstances(serviceType)
.Select(instance => (TService)instance);
}
Which in turn calls:
public IEnumerable<object> GetAllInstances(Type serviceType)
{
lock (_factories)
{
if (_factories.ContainsKey(serviceType))
{
foreach (var factory in _factories[serviceType])
{
GetInstance(serviceType, factory.Key);
}
}
}
if (_instancesRegistry.ContainsKey(serviceType))
{
return _instancesRegistry[serviceType].Values;
}
return new List<object>();
}
Basically, all that it's doing is checking to see if your type exists in one or more dictionaries. It's a straight comparison so whether an object A inherits from object B isn't taken into account.
What you could do, which requires more effort, but will do what you want, is use the Messenger to send a "Cleanup" message to all of your subscribing viewmodels:
ViewModelLocator:
public static void Cleanup()
{
Messenger.Default.Send<CleanUp>(new CleanUp());
}
ViewModel:
public class MainViewModel : ViewModelBase
{
public MainViewModel(LocalServer server)
{
this.Server = server;
Messenger.Default.Register<CleanUp>(this,CallCleanUp);
}
private void CallCleanUp()
{
CleanUp();
}
This will work. If you want to make it automatic then create a class that inherits from ViewModelBase that has this logic in it and have all you other viewmodels inherit from this class instead of ViewModelBase.
Upvotes: 10