Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force Cleanup() for all my ViewModels

Tags:

mvvm-light

My ViewModel instantiate resource that must be released when the program exits.

this in all my ViewModels:

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();
    }
}

this in ViewModelLocator

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.

like image 816
user1528311 Avatar asked Jul 20 '12 11:07

user1528311


1 Answers

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.

like image 176
Faster Solutions Avatar answered Oct 27 '22 07:10

Faster Solutions