MVVM Light Locator:注册 ViewModelBase 的所有派生类

MVVM Light Locator: Register all derivates of ViewModelBase

这是我的定位器。出于演示目的,我去除了除两个之外的所有 ViewModel。因为我基本上需要注册所有 : ViewModelBase 对象,所以我正在考虑使用 reflection 来做到这一点。 class本身的属性不能像这样"created",但是注册可以。但是,我正在努力思考这里的泛型方法。

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

像往常一样,制定一个正确的问题需要我深入挖掘,所以一段时间后我想出了 ViewModelLocator 构造函数的代码。我想分享它,因为我觉得这至少是 有点 常见的 MVVM Light 问题,我还没有找到任何解决方案。

  • 首先,从所有程序集中检索所有类型的 ViewModelBase
  • 然后,我们需要获取SimpleIocRegister方法。现在,我没有比 "find" 使用 .Where 更好的主意了。 请随时改进此声明!
  • 最后,我使用 MakeGenericMethodViewModelBase 派生类型。

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]);

...以及 ViewModelLocator class 顶部的属性:我不认为它可以通过反射和滥用 XAML 来完成,因为这看起来不太好给我练习。但是,为了让生活更轻松,我创建了一个简单的方法。

singleton参数定义实例是否应该是单一的,或者每次都获得一个唯一的键。我在我的应用程序中将 MainWindow 定义为单例,而其他 ViewModel 在我的场景中不是单例。

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