MVVM Light, Ninject в основном в области уведомлений - PullRequest
2 голосов
/ 16 октября 2011

Мне нужен совет по архитектуре приложения.

Я создаю настольное приложение .Net 4 WPF с поддержкой значков области уведомлений.

Приложение имеет несколько окон, которые появляются при запуске,затем закройте, и останется только значок области уведомлений.

Значок области уведомлений является чисто WPF-контролем, который я получил от этого примера кода проекта.

Так как мое приложение должно работать, даже когда все окна закрыты, у меня естьустановите

ShutdownMode="OnExplicitShutdown"

в App.xaml.

Я опишу мою идею архитектуры и механизма запуска, и вы скажете мне, где я иду не так, и исправьте меня, если это возможно.

В App.xaml.cs я создаю Ninject StandardKernel, назовем его appKernel и загружаем в него модули Ninject.Сначала Ninject должен разрешить только один интерфейс - экземпляр heartbeatManager.HeartbeatManager - это класс, для которого я планирую использовать:

a) Размещение моего экземпляра NotifyIcon в качестве переменной поля, чтобы он был виден, пока экземпляр класса находится в памяти.

b) Реализация события shutdown, на которое я подпишусь в app.xaml.cs, и явно отключаю приложение, когда его запрашивает класс heartbeat.

В этот момент создается экземпляр heartbeatManager, оставленный для зависания в памяти.

В App.xaml я установил StartupUri="MainWindow.xaml", чтобы создать и отобразить MainWindow.Следуя шаблону MVVM Light ViewModelLocator, MainWindow пытается разрешить свой контекст данных из статического экземпляра ViewModelLocator, определенного в App.xaml:

<Application.Resources>
    <ViewModels:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</Application.Resources>

Создается экземпляр ViewModelLocator и в конструкторе инициализируется другой StandardKernel (Есть ли какой-либо другой тип ядра, которое я сейчас использую? ), который будет использоваться для разрешения привязок модели представления.Модель представления MainWindow предоставляется для удовлетворения запроса окон, и все приложение продолжает работать.

Очень важное значение заключается в том, что экземпляр hearbeatManger привязан к определению интерфейса в одной области видимости, так что представления моделейкоторые требуют его в качестве параметра конструктора, могут разрешить и получить уже созданный экземпляр.Будет ли работать такое разрешение зависимостей, если модель представления и heartbeatManager загружены в разные ядра?Если нет, то как я могу решить эту проблему?

Является ли вышеописанный сценарий хорошим с точки зрения архитектуры, реализуемым ли он в коде, или я допустил ошибку, когда размышлял над архитектурой?

1 Ответ

3 голосов
/ 16 октября 2011

... В этот момент создается экземпляр heartbeatManager, оставленный для зависания в памяти ...

Если оно зарегистрировано в вашем ядре, это не магия, которая заставляет его зависать в памяти - он будет держаться до тех пор, пока это делает ядро ​​/ контейнер. Этот контейнер, вероятно, должен быть членом вашего класса App, поскольку ваш класс приложения остается неизменным до тех пор, пока (* сгенерированный компилятором) метод Main делает, и вы все равно должны утилизировать его при завершении работы приложения.

... Следуя шаблону MVVM Light ViewModelLocator, MainWindow пытается разрешить свой контекст данных из статического экземпляра ViewModelLocator, определенного в App.xaml ...

Я не уверен, что это будет хорошо сочетаться с NInject. Это контейнер Dependency Injection, а не контейнер Service Locator (хотя он и используется под капотом). Основная цель NInject (и аналогичных сред) - не требовать от вас использования шаблона Service Locator и вместо этого вводить все ваши зависимости.

... Создается экземпляр ViewModelLocator, и в конструкторе он инициализирует другой StandardKernel ...

Если ваш сценарий не является достаточно сложным (что на самом деле не подходит для этого приложения), то я предлагаю придерживаться одного ядра NInject.

Предлагаемое решение

Сам класс локатора модели представления ничего не делает для вас, кроме как позволяет разделить логику инициализации и выполнять выборочную инициализацию в зависимости от того, находитесь ли вы в режиме разработки или во время выполнения. Вы можете добиться того же с модулями NInject (которые статья локатора модели представления, которую вы связали в комментариях, уже использует ).

Я предлагаю вместо использования локатора модели представления указать все ваших компонентов в классе вашего модуля и выполнить логику IsInDesignMode в методе Load.

Это может быть немного сложнее с MVVM, поскольку модель представления должна быть привязана к свойству object, которое вы не создали и не можете аннотировать.

Есть несколько способов решить эту проблему непосредственно в NInject вместо обращения к локатору службы:

  • Используйте Dependency Injection для вашего представления, для этого требуется модель представления. Если это не работает с использованием инжектора конструктора (как вы упомянули в комментариях), используйте вместо него инъекцию свойства с пользовательским свойством, которое перенаправляет его установщик в DataContext.
  • Используйте NВведите фабричные методы (ToMethod) для создания своего вида и привяжите модель вида к виду в каждом фабричном методе.
    Например. Bind<MainView>().ToMethod(context => new MainView() { DataContext = new MainViewModel() });

Если вы можете, я бы пошел на второй метод. Таким образом, ваше представление не должно обрабатывать привязку данных и не должно иметь никакого кода позади. Это также просто понять, что позволит вам избежать необходимости регистрировать как представления, так и модели представления в ядре, и позволит вам избежать создания какого-либо хорошо известного интерфейса для вашей модели представления.

...