2017-01-04 10 views
1

В моем приложении (приложение WPF на основе MVVM-архитектуры) я использую много ICommand с, как услуг. Некоторые из этих команд могут быть привязаны к пунктам меню, панелям инструментов, столбцам состояния и т. Д., Где они вводятся в соответствующие модели просмотра контейнеров. Теперь некоторые из них, например, могут манипулировать данными в оболочке приложения, поэтому Shell является их зависимостью. Поскольку Shell также содержит указанные контейнеры (меню, строка состояния ...), я получаю циклическую зависимость. (Shell -> Меню -> Command -> Shell).Круговые зависимости и инверсия управления - как их решить?

В настоящее время я использую MEF для составления моего приложения, поэтому большую часть времени проблема может быть решена с помощью использования частной или частной инъекции, но у меня такое ощущение, что это своего рода неприятная практика (услуга не имеет никакого способа говоря родителям, что ему нужна эта зависимость, даже если это так).

Мой вопрос: Что является распространенным способом решить проблему так:

class Shell : IShell 
    .ctor(IMenu) 

class Menu : IMenu 
    .ctor(ICommand[]) 

class ExitCommand : ICommand 
    .ctor(IShell) 
+0

Два общих способа вызова команды из модели родительского представления ('Shell') или глобально доступные команды являются реализациями EventAggregator (' PubSubEvent' в 'Prism') или' CompositeCommand' (из 'Prism' снова). – mechanic

+0

Что такое «Шелл»? Не могли бы вы описать это больше? – Joe

+0

@Joe Оболочка - это в основном модель представления, которая выступает в качестве контейнера для всех других компонентов вида. – artganify

ответ

1

Я никогда не использовал MEF, но использовать инъекционный контейнер зависимостей и столкнулись с подобными проблемами. Проблема в том, что (я думаю), что вы бросаете свою оболочку в качестве службы (предоставляя функциональность выхода), но она также действует как ViewModel (отображение меню и т. Д.). Он берет на себя большую ответственность, что и должен.

Давайте разделим ваш приема всей интерфейс «Ishell» на отдельные модули, чтобы продемонстрировать, что:

class Shell : IShell, IExitManager 
    .ctor(IMenu) 

class Menu : IMenu 
    .ctor(ICommand[]) 

class ExitCommand : ICommand 
    .ctor(IExitManager) 

Ваша оболочка делает две вещи сразу, это ViewModel материал (Ishell), и это управление выходом (IExitManager).

Что бы я хотел сделать, это отвлечь функциональность от вашего ViewModel. Я бы создал специальный сервис IExitManager. Вместо того, чтобы сделать ShellViewModel реализовать эту функциональность и впрыснуть все это в места, которые должны только запускать событие выхода (перетаскивая функциональность меню вдоль и заставляя круговые зависимости), вместо этого иметь эту функциональность в выделенном IExitManager.

Вместо того, чтобы ваш текущий:

enter image description here

Вместо принести услуги из реализации Shell:

enter image description here

Ваш класс IExitManager нужно будет выставить такую ​​же функциональность как вы в настоящее время иметь в IShell (я предполагаю метод Exit()) и обработчик событий ExitRequestedHandler для вашей Shell для прослушивания и выполнения это действие.

EventAggregator - это в основном более общая версия этого - я бы порекомендовал вам взглянуть на это. Вы можете заставить свою Службу прослушивать события EventExit и команду, выдающую их. Единственной общей зависимостью является служба EventAggregator. То, что это решение делает, является «одной» версией этого только для событий выхода. Если вы делаете это, используйте EventAggregator.

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

  • Нет связанных вопросов^_^