tesla1060
tesla1060

Reputation: 2765

MVVMLight ViewModelLocator to create new ViewModel

I have been following the mvvmlight to code a project. I have 3 xaml files MainWindow, View1, View2,

I have registered all three viewmodels in my ViewModelLocator, as well as a data service used by View1Model

    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        SimpleIoc.Default.Register<IView1Service, View1Service>();
        SimpleIoc.Default.Register<MainViewModel>();
        SimpleIoc.Default.Register<View1Model>();
        SimpleIoc.Default.Register<View2Model>();
    }

    public MainViewModel Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>(Guid.NewGuid().ToString());
        }
    }
    public View1Model View1
    {
        get
        {
            return ServiceLocator.Current.GetInstance<View1Model >(Guid.NewGuid().ToString());
        }
    }
    public View1Model View2
    {
        get
        {
            return ServiceLocator.Current.GetInstance<View2Model >(Guid.NewGuid().ToString());
        }
    }

The View1Model requires a IView1Service as constructor input,

   public View1Model(IView1Service view1Service)
    {
        _view1_service = view1Service;
    }

In my App.xaml I have registered them as below

<Application.Resources>
    <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    <DataTemplate DataType="{x:Type vm:View1Model}">
          <views:view1 />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:View2Model}">
          <views:View2 />
    </DataTemplate>
</Application.Resources>

And of course View1 View2 are xmal files under the MyProject.View namespace.

I was trying to initialize all the views in my MainViewModel, so I access all the viewmodel instances in MainViewModel

    public MainViewModel()
    {
        // Add available pages
        PageViewModels.Add(new View1Model(new View1Service()));  // <========How to get this from the ViewModelLocator ?
        PageViewModels.Add(new View1Model());

        // Set starting page
        CurrentPageViewModel = PageViewModels[0];

    }

PageViewModels.Add(new View1Model()); in this line of code, I was hoping to get it from ViewModelLocator instead of passing a View1Service object. But the Locator I registered in App.xaml is not accessible here, what is the best to way to work around this problem?

Upvotes: 1

Views: 2965

Answers (2)

Ryan
Ryan

Reputation: 815

I've using MVVMLight to developed for the Universal App, not WPF. But I guess it should be similar.

You don't have to explicitly create a new instance of the ViewModel. It is a Singleton, so a instance will be created when ServiceLocator.Current.GetInstance<T>() is first called.

Also, SimpleIoc is smart enough to find a suitable class (match the type that register before, IView1Service in this case) to instantiated if it needs a parameter.

The Locator you registered in App.xaml is used in other xaml, like:

<Page
...
DataContext="{Binding View1, Source={StaticResource Locator}}"
>

To get the ViewModel instance in code, just like @goobering 's answer.

View1Model vm = (new ViewModelLocator()).View1;

It is safe to create many ViewModelLocator instances, and the ViewModel returned is the same object.

Upvotes: 3

goobering
goobering

Reputation: 1553

I do this by creating the ViewModelLocator as a private field in my ViewModel

public class MyViewModel : ViewModelBase
{
    private ViewModelLocator _locator;

    public MyViewModel()
    {
        _locator = new ViewModelLocator();
    }
}

Then you can access your ViewModels through your ViewModelLocator using: _locator.View1, _locator.View2, etc.

Upvotes: 1

Related Questions