2014-10-29 35 views
1

我正在更换MVVM Light默认SimpleIOCAutofac。到目前为止这么好,但现在我试图初始化一个ViewModel的应用程序开始,因为我需要登记一些调用MessengerInstance,与SimpleIOC这很容易SimpleIoc.Default.Register<MyViewModel>(true);,但我无法找到与Autofac的方式。立即使用Autofac创建ViewModel实例

我想containerBuilder.RegisterType<MyViewModel>().AutoActivate();初始化视图模型,但随后它没有注册,当我需要它绑定:

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

编辑

的问题是,我想要的视图模型来我前被激活解决它,因为我在那里注册一条消息:

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

如果ViewModel不是r在这一点上egistered将丢失的消息:

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

我不明白这个问题。你为什么使用'AutoActivate'?我想你只需要将实例注册为常规注册并解决它。 – 2014-10-29 15:20:58

+0

但是,如果您的视图绑定到您的ViewModel,这是不是意味着只要您导航到视图,VM上的ctor就会被调用,此时MessengerInstance将知道如何处理发送的消息? – Darek 2014-10-29 16:20:14

+0

@Darek导航是异步的 – 2014-10-29 16:47:49

回答

3

这似乎完全正常工作:

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

你必须使用AutoActivate?换句话说,是否有特定的需求需要通过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 . . . 

如果你需要运行一些code at startup, consider IStartable

public class StartupMessageWriter : IStartable 
{ 
    public void Start() 
    { 
     Console.WriteLine("App is starting up!"); 
    } 
} 

.... 

var builder = new ContainerBuilder(); 
builder 
    .RegisterType<StartupMessageWriter>() 
    .As<IStartable>() 
    .SingleInstance(); 

UPDATE

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

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

脏,但作品。

+0

感谢所有的信息,我已经在尝试双注册,但感觉有点奇怪。 – 2014-10-29 16:00:21

+0

最初我觉得很奇怪,但在阅读文档后,这种行为是可以理解的。基本上,AutoActivate会为你创建和配置实例,但它不会保留下来供以后使用。因此,要么“自动激活”自己,要么使用IStartable执行任何类型的初始化,或使用双重注册。 – Darek 2014-10-29 16:08:32

+0

这将ioc容器紧密地耦合到虚拟机,而去真正的反转和DI,你应该让容器用你需要的所有依赖来构造你的对象 - 这使得这种方法实际上是一种反模式...这将是很好的解决,如果你在回答中解决了这个问题(通过例如ctor制作MyVM)。 – 2015-08-03 12:20:18