Создать экземпляр ViewModel немедленно с Autofac

1

Я заменяю 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);
  • 1
    Я не понимаю проблемы. Почему вы используете AutoActivate ? Я думаю, вам просто нужно зарегистрировать экземпляр как обычную регистрацию и решить ее.
  • 0
    Но если ваше представление связано с вашей ViewModel, не означает ли это, что ctor на виртуальной машине будет вызываться, как только вы перейдете к своему представлению, в какой момент MessengerInstance будет знать, что делать с отправляемым сообщением?
Показать ещё 5 комментариев
Теги:
dependency-injection
autofac
mvvm-light

1 ответ

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 . . .

Если вам нужно запустить код при запуске, рассмотрите 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>());
    }
}

Грязный, но работает.

  • 0
    Спасибо за всю информацию, я уже пробовал двойную регистрацию, но это было немного странно.
  • 0
    Изначально мне это показалось странным, но после прочтения документации поведение стало понятным. По сути, AutoActivate создаст и утилизирует экземпляр для вас, но не сохранит его для последующего использования. Итак, либо «автоматически активируйте» себя, либо используйте IStartable для выполнения любого типа инициализации, либо используйте двойную регистрацию.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню