使用Autofac立即创建ViewModel实例

本文关键字:ViewModel 实例 创建 Autofac 使用 | 更新日期: 2023-09-27 18:28:22

我将用Autofac替换MVVM Light默认的SimpleIOC。到目前为止还不错,但现在我正试图在应用程序启动后立即初始化一个ViewModel,因为我需要用MessengerInstance和SimpleIOC注册一些调用,这和SimpleIoc.Default.Register<MyViewModel>(true);一样简单,但我找不到使用Autofac的方法。

我尝试了初始化ViewModel的containerBuilder.RegisterType<MyViewModel>().AutoActivate();,但当我需要它进行绑定时,它没有注册:

    containerBuilder.RegisterType<MyViewModel>().AutoActivate();
    ...
    public MyViewModel MyVM
    {
        get { return this.container.Resolve<MyViewModel >(); } //<- Boom! ComponentNotRegisteredException!!
    }

编辑

问题是,我希望在解决ViewModel之前激活它,因为我在那里注册了一条消息:

public MyViewModel()
{
        MessengerInstance.Register<bool>(this,(b) => DoThisAction(b));
}

如果ViewModel此时未注册,则消息将丢失:

//MyView is binded to MyViewModel
NavigationService.NavigateTo("MyView);
MessengerInstance.Send<bool>(true);

使用Autofac立即创建ViewModel实例

这似乎运行得很好:

internal class Program
{
    public static IContainer container;

    public MyViewModel MyVM
    {
        get { return Program.container.Resolve<MyViewModel>(); }
    }
    private static void Main(string[] args)
    {
        ContainerBuilder containerBuilder = new ContainerBuilder();
        containerBuilder.RegisterType<MyViewModel>();
        container = containerBuilder.Build();
        Program p = new Program();
        MyViewModel vm = p.MyVM;
    }
}

你必须使用自动激活吗?换句话说,在Build事件中,是否有特定的需要通过构造函数?

来自Autofac文档:

自动激活的组件是一个只需要在构建容器时激活一次。这是一个"温暖的开始"没有调用组件上的方法并且没有接口需要实现-组件的单个实例将在不引用所持有的实例的情况下进行解析。

因此,在我看来,如果你使用AutoActivation,注册的类型将不会保存在生成器注册表中,所以你必须重新注册它。

如果你绝对需要它,那么它必须注册两次:

internal class Program
{
    public static IContainer container;

    public MyViewModel MyVM
    {
        get { return Program.container.Resolve<MyViewModel>(); }
    }
    private static void Main(string[] args)
    {
        ContainerBuilder containerBuilder = new ContainerBuilder();
        Console.WriteLine("Before register");
        containerBuilder.RegisterType<MyViewModel>().AutoActivate();
        containerBuilder.RegisterType<MyViewModel>();
        container = containerBuilder.Build();
        Program p = new Program();
        Console.WriteLine("Before property retrieval");
        MyViewModel vm = p.MyVM;
    }
}
internal class MyViewModel
{
    public MyViewModel()
    {
        Console.WriteLine("MyViewModel");
    }
}

结果:

Before register
MyViewModel
Before property retrieval
MyViewModel
Press any key to continue . . .

如果您需要在启动时运行一些代码,请考虑IStartable:

public class StartupMessageWriter : IStartable
{
   public void Start()
   {
      Console.WriteLine("App is starting up!");
   }
}
....
var builder = new ContainerBuilder();
builder
    .RegisterType<StartupMessageWriter>()
    .As<IStartable>()
    .SingleInstance(); 

更新

如果你绝对必须,你可以迭代所有的注册:

foreach (var r in container.ComponentRegistry.Registrations)
{
     var dump = container.ResolveComponent(r, Enumerable.Empty<Parameter>());
}

如果你的ViewModels实现了一个基类,你可以使用:

foreach (var r in container.ComponentRegistry.Registrations)
{
    if (r.Target.Activator.LimitType.IsSubclassOf(typeof (ViewModel)))
    {
        var dump = container.ResolveComponent(r, Enumerable.Empty<Parameter>());
    }
}

脏,但有效。