2014-10-29 2 views
1

Я заменяю MVVM Light по умолчанию SimpleIOC с Autofac. Пока что так хорошо, но теперь я пытаюсь инициализировать один ViewModel, как только начнется приложение, так как мне нужно зарегистрировать некоторые вызовы с помощью MessengerInstance, с SimpleIOC это было так же просто, как SimpleIoc.Default.Register<MyViewModel>(true);, но я не могу найти путь с Autofac ,Создать экземпляр ViewModel непосредственно с Autofac

Я попытался containerBuilder.RegisterType<MyViewModel>().AutoActivate();, инициализирующий ViewModel, но тогда он не зарегистрирован, когда мне это нужно для связывания:

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

Редактировать

Вопрос заключается в том, что я хочу ViewModel быть активирован до I разрешите это, потому что я регистрирую там сообщение:

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'? Думаю, вам просто нужно зарегистрировать экземпляр как обычную регистрацию и решить эту проблему. –

+0

Но если ваше представление привязано к вашей ViewModel, не означает ли, что ctor на VM будет вызван, как только вы перейдете к своему представлению, в какой момент MessengerInstance будет знать, что делать с отправляемым сообщением? – Darek

+0

@Darek Навигация асинхронна –

ответ

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

Спасибо за всю информацию, я уже пробовал двойную регистрацию, но это было немного странно. –

+0

Первоначально это было странно для меня, но после чтения документации поведение понятно. В принципе, AutoActivate создаст и удалит экземпляр для вас, но он не будет поддерживать его для последующего использования. Таким образом, либо «автоматически активируйте» себя, либо используйте IStartable для выполнения любого требуемого типа инициализации или используйте двойную регистрацию. – Darek

+0

это плотно соединяет ioc-контейнер с виртуальной машиной, тогда как для реальной инверсии и DI вы должны позволить контейнеру построить свой объект со всеми необходимыми зависимостями, что делает этот подход буквально анти-шаблоном ... было бы хорошо обратиться, если бы вы ответили на эту проблему в своем ответе (сделав «MyVM» инъектируемой, например, ctor). –

Смежные вопросы