简体   繁体   中英

MVVM Light Locator: Register all derivates of ViewModelBase

This is my locator. For demonstration purposes, I stripped all ViewModels except two. Since I basically need to register all : ViewModelBase objects, I was thinking of using reflection to do this. The properties of the class itself can't be "created" like this, but the registration can. However, I'm struggling with reflection on generic methods here.

using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using System;

namespace DevExplorer
{
    public class ViewModelLocator
    {
        public WindowMainViewModel WindowMain => SimpleIoc.Default.GetInstance<WindowMainViewModel>();
        public WindowAboutViewModel WindowAbout => ServiceLocator.Current.GetInstance<WindowAboutViewModel>(GetKey());

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

            //REFACTOR: Get by reflection
            SimpleIoc.Default.Register<WindowMainViewModel>();
            SimpleIoc.Default.Register<WindowAboutViewModel>();
        }

        private string GetKey()
        {
            return Guid.NewGuid().ToString();
        }
    }
}

Like usually, formulating a proper question required me dig in deeper, so after some time I came up with this code for the ViewModelLocator constructor. And I would like to share it, since I feel this is an at least somewhat common MVVM Light problem that I haven't found any solution to, yet.

  • First, all types of ViewModelBase are retrieved from all assemblies.
  • Then, we need to get the Register method of SimpleIoc . For now, I have no better idea than to "find" it using .Where . Please feel free to improve this statement!
  • Finally, I used MakeGenericMethod with the type of the ViewModelBase derivate.

Type[] viewModels = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(assembly => assembly.GetTypes())
    .Where(type => typeof(ViewModelBase).IsAssignableFrom(type) && type != typeof(ViewModelBase))
    .ToArray();

MethodInfo registerMethod = typeof(SimpleIoc)
    .GetMethods()
    .Where(method => method.Name == nameof(SimpleIoc.Default.Register) && method.GetParameters().Length == 0 && method.GetGenericArguments().Length == 1)
    .First();

foreach (Type viewModel in viewModels)
{
    registerMethod
        .MakeGenericMethod(viewModel)
        .Invoke(SimpleIoc.Default, new object[0]);

...And with the properties at the top of the ViewModelLocator class: I don't think it can be done with reflection and misusing XAML for this doesn't seem like good practice to me. But, to make life easier, I created a simple method.

The singleton parameter defines whether or not the instance should be single or get a unique key each time. I defined the MainWindow as singleton in my application and the other ViewModels are not singletons in my scenario.

public WindowMainViewModel WindowMain => GetInstance<WindowMainViewModel>(true);
public WindowAboutViewModel WindowAbout => GetInstance<WindowAboutViewModel>(false);

private static TService GetInstance<TService>(bool singleton)
{
    return ServiceLocator.Current.GetInstance<TService>(singleton ? null : Guid.NewGuid().ToString());
}

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