简体   繁体   中英

Correct way of getting unique ViewModels from MVVM Light ViewModelLocator

In my UWP app im using MVVM Light and its ViewModelLocator to get ViewModels.

My ViewModelLocator looks like this, im passing guid to GetInstance to get unique VM.

    public class ViewModelLocator
    {
        static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<MyViewModel>();
        }
        public MyViewModel MyVM => ServiceLocator.Current.GetInstance<MyViewModel>(Guid.NewGuid().ToString());
    }

I have usercontrol which needs to have unique VM, as I can have multiple instances of this user control in my app. Here is how im getting the ViewModel:

<UserControl x:Class="My.App.Controls"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             DataContext="{Binding Path=MyVM, Source={StaticResource ViewModelLocator}}">
             ...
</UserControl>

Is this the correct way of getting unique VM's? Or are the VM's still cached, not disposed, even when my user control is not used any more?

UPDATE

So it seems that my code works ok, I get unique MyVM instance every time.

Now the question is, what is the correct way to unregistered/dispose view model.

I can do it with SimpleIoc.Default.Unregister(guid) but with my current implementation it is not very straight forward to deliver Guid (which was used in creating VM) to my user control, so I can unregister the VM.

Overall if I just create my VM runtime im ViewModelLocator with out SimpleIoc, is there any other drawbacks than losing dependency injection?

    public class ViewModelLocator
    {
        public MyViewModel MyVM => new MyViewModel();
    }

I assume your UserControl must be used by some View (window).

The ViewModel controlling that View could spawn the required ViewModels for the UserControl. You could bind the UserControl to this 'SubViewModel' property and also dispose of them however you then wished.

You can add an additional property to your view model and call a custom removal method in the view disposing your view model.

The modified getter for the view model looks like this:

    public MyViewModel MyVM
    {
        get
        {
            String id = Guid.NewGuid().ToString();
            var instance = SimpleIoc.Default.GetInstance<MyViewModel>(id);
            instance.ID = id;
            return instance;
        }
    }

The method for disposing the view model locator looks like this:

    public static void UnregisterMyVM(String id)
    {
        SimpleIoc.Default.Unregister<MyViewModel>(id);
    }

In your view you got to listen for closing events and call the unregistration method there:

    public MyView()
    {
        InitializeComponent();

        this.Closed += ((sender, arguments) =>
        {
            var viewModel = ((MyViewModel)this.DataContext);
            viewModel.Dispose();
            ViewModelLocator.UnregisterSourceCodeViewer(viewModel.ID);
            this.DataContext = null;
        });
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM