Я заменяю MVVM Light по умолчанию SimpleIOC на Autofac. Пока что так хорошо, но теперь я пытаюсь инициализировать один ViewModel, как только приложение запустится, так как мне нужно зарегистрировать некоторые вызовы с MessengerInstance
, с SimpleIOC это было так же просто, как SimpleIoc.Default.Register<MyViewModel>(true);
, но я не могу найти путь с Autofac.
Я попробовал containerBuilder.RegisterType<MyViewModel>().AutoActivate();
который инициализирует ViewModel, но затем он не регистрируется, когда мне это нужно для привязки:
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);
Кажется, это работает отлично:
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 . . .
Если вам нужно запустить код при запуске, рассмотрите 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>());
}
}
Грязный, но работает.
AutoActivate
? Я думаю, вам просто нужно зарегистрировать экземпляр как обычную регистрацию и решить ее.