Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVMLight ViewModelLocator registering dataservice

This question might look naive, but I couldn't understand this code in the ViewModelLocator.cs file:

static ViewModelLocator()
{
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

    if (ViewModelBase.IsInDesignModeStatic)
    {
        SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
    }
    else
    {
        SimpleIoc.Default.Register<IDataService, DataService>();         
    }

    SimpleIoc.Default.Register<MainViewModel>();
}

I see that we use a DataService to get data (from WCF service for example) and assigning it to the MainViewModel. But what if I'm registering more than one ViewModel? like this:

static ViewModelLocator()
{
    ....
    SimpleIoc.Default.Register<MainViewModel>();
    SimpleIoc.Default.Register<Page2ViewModel>();
}

and let's say I have another DataService (DataService2 for example), but this one I'll use with the Page2ViewModel. how can I do that?

Also, if someone can help me (or even give me a link to read) about the above code. I have no clue what it means.

like image 827
Qirat Avatar asked Jan 29 '12 09:01

Qirat


People also ask

What is viewmodellocator in MVVM?

In some MVVM applications (and notably apps based on the MVVM Light toolkit), a class named ViewModelLocator is used to create and expose some of the application’s ViewModels. This is a convenient location in which to register most of the services and service consumers. In fact, some ViewModels can also be registered with the IOC container.

What is MVVM light lightweight framework?

MVVM Light lightweight framework allows developers to choose which components they want to use. (like ViewModel Locator, Navigation Service, Dialogue Service) Start by creating a new Xamarin.Forms project.

How do I open MVVM light in Visual Studio?

Then, in Visual Studio, right-click MainPage.xaml in Solution Explorer, and select either Open in Blend or View in Designer. The same UI is shown, this time with the text “Welcome to MVVM Light [design].”

What is the difference between ViewModel and navigationservice?

Of course, a ViewModel is a plain object so it does not have such a built-in property, and here again the IOC container comes handy: the NavigationService is registered in the ViewModelLocator, cached in the IOC container and can be injected into each ViewModel as needed.


1 Answers

You are not assigning any IDataService to the MainViewModel here. You are registering a type mapping, so your container will be aware that it should return a DataService whenever an IDataService required.

This is related to dependency injection http://en.wikipedia.org/wiki/Dependency_injection

The DI container auto-wires the dependencies, so when you need a specific type, you can call

ServiceLocator.Current.GetInstance<IDataService>()

or

ServiceLocator.Current.GetInstance<MainViewModel>()

etc. If it can build it (so you registered your types), it will resolve the full dependency graph for you.

For example, if your MainViewModel has a constructor dependency on IDataService, and you are not in design mode, a DataService will be injected to the MainViewModel constructor. Don't be afraid from the buzzword injected, it is just a call to the MainViewModel constructor with the appropriate parameters :).

So, MainViewModel will not interference with Page2ViewModel here.

I made a simple sample for you to demonstrate what happens (I used Unity, http://unity.codeplex.com/ , but the syntax is almost the same):

class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IService, Service1>();
        container.RegisterType<IService, Service2>("MySpecificService");
        container.RegisterType<IRepository, Repository>();
        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));

        var viewModel = ServiceLocator.Current.GetInstance<MainViewModel>();
        viewModel.Foo();
    }
}

interface IService
{
}

interface IRepository
{   
}

class Service1 : IService
{
    public Service1(IRepository repository)
    {
        Console.WriteLine("Service1 created");
    }
}

class Service2 : IService
{
    public Service2()
    {
        Console.WriteLine("Service2 created");
    }
}

class Repository : IRepository
{
    public Repository()
    {
        Console.WriteLine("Repository created");
    }
}

class MainViewModel
{
    public MainViewModel(IService service)
    {
        Console.WriteLine("MainViewModel created");
    }

    public void Foo()
    {
        var specificService = ServiceLocator.Current.GetInstance<IService>("MySpecificService");
    }
}

the output is:

Repository created
Service1 created
MainViewModel created
Service2 created

Because you need a MainViewModel (maybe in SimpleIoC you need to register MainViewModel too, in Unity, it can resolve concrete classes without mapping), the container trying to create one, but it realizes that MainViewModel needs an IService, and it finds the default one from the mapping, which is Service1, but it realizes that Service1 needs an IRepository, and it finds the default one, so it can pass a Repository to the Service1 constructor, then the Service1 instance to the MainViewModel constructor. All the dependencies resolved.

The Foo call is an example how you can register more than one type to the same interface. Dependency injection is a much more bigger topic, but auto-wiring is an important part of it.

like image 121
Peter Porfy Avatar answered Sep 27 '22 22:09

Peter Porfy