2014-10-29 93 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