Prism / MVVM (MEF / WPF): предоставление навигации [например, меню] из модулей - PullRequest
12 голосов
/ 14 ноября 2010

Я начинаю свой первый набег в мир Prism v4 / MVVM с MEF & WPF.Я успешно создал оболочку и, используя MEF, я могу обнаружить и инициализировать модули.Однако я не уверен, как правильно обеспечить навигацию для представлений, представленных этими модулями.

Например, предположим, что один из модулей предоставляет три представления, и я хочу отображать навигацию для этих представлений науправление меню.До сих пор я успешно раскрыл представление, основанное на MenuItem, и это MenuItem содержит дочерние MenuItem элементы управления, таким образом обеспечивая иерархию команд, которую можно использовать.Отлично.

Дело в том, что это неправильно.Сейчас я заявляю в моем модуле, что навигация (и, следовательно, оболочка) ДОЛЖНА поддерживать использование меню.Что если я захочу перейти на использование ToolBar или даже Ribbon.Затем мне пришлось бы изменить все свои модули, чтобы открыть соответствующие типы элементов управления для оболочки.

Я огляделся вокруг, и на некоторых сайтах упоминается использование «Сервиса» для обеспечения навигации, причем во времяПри инициализации модуля к сервису добавляются опции навигации, которые, в свою очередь, используются оболочкой для отображения этой навигации в любом нужном формате (ToolBar, TreeView, Ribbon, MenuItem и т. д.) - ноЯ не могу найти никаких примеров того, как на самом деле это сделать.

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

Что мне нужно знать, так это: что будет правильным путемраскрывать параметры навигации таким образом, чтобы не настаивать на поддержке определенного элемента управления оболочкой, и если сервис - это путь, то как можно объединить это в шаблонах Prism / MVVM.

Заранее спасибо за любые идеи, которые вы можете предложить.

Ответы [ 4 ]

7 голосов
/ 21 ноября 2010

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

public interface IMenuService {
    void AddItem(string name, Action action);
    IEnumerable<MenuItemViewModel> GetItems { get; }
}

Создать 1 реализацию и один экземпляр.

public class MenuService : IMenuService {

    private readonly IList<MenuItemViewModel> items = new List<MenuItemViewModel>();

    void AddItem(string name, Action action) {
        items.Add(new MenuItemViewModel {
            Name = name,
            Action = action
        });
    }

    IEnumerable<MenuItemViewModel> GetItems {
        get { return list.AsEnumerable(); }
    }
}

В своих модулях используйте MEF для разрешения этого экземпляра и вызовите AddItem() для регистрацииваши взгляды.Свойство Action представляет собой простой делегат для активации представления или выполнения каких-либо других действий.

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

1 голос
/ 21 ноября 2010

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

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

Из-за этого модули должны быть спроектированы так, чтобы взаимодействовать с оболочкой для размещения контента в именованных областях, и поэтому я не вижу причин, по которым модули не должны предоставлять доступ к любому типу навигации, поддерживаемой оболочкой.

Таким образом, мои модули (в настоящее время) предоставляют «RibbonView» (RibbonTab) с необходимыми значками, кнопками, командами и т. Д., Чтобы раскрыть функциональные возможности модуля. Каждый «RibbonView» регистрируется в «RibbonRegion» оболочки вместе с подсказками для упорядочивания, и затем это отображается в оболочке.

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

Я просто надеюсь, что при этом я не нарушу ни одного из принципов составного приложения, но при этом я никогда не нашел шаблон, который на самом деле может быть реализован в реальном сценарии без некоторой «интерпретации».

Мне было бы интересно узнать, есть ли у кого-нибудь мнение по этому поводу.

0 голосов
/ 02 декабря 2010

Эта статья использует абстракцию (IMenuItem) для представления ViewModels для ваших вариантов меню. Как вы на самом деле визуализируете эти импортированные объекты, зависит от главного приложения. В этом примере используется меню WPF, но вы, безусловно, можете отобразить его так, как хотите, потому что IMenuItem достаточно абстрактно.

Если вы изменили IMenuItem на INavigationItem, вы получите то, что хотите.

В этой статье, когда конкретный элемент навигации получает уведомление о том, что он «запущен», он обычно создает экземпляр ViewModel для документа или «панели» и передает его службе ILayoutManager. Он имеет подключаемую архитектуру, поэтому вы можете поменять сервис LayoutManager для другого механизма компоновки (по умолчанию используется оболочка AvalonDock).

0 голосов
/ 02 декабря 2010

Я столкнулся с такой же ситуацией, и я думаю, что решение заключается в разграничении интерфейса и реализации.Например, вы можете создать представление в модуле, который выполняет данную функцию.Это все, что он делает.Как только вы используете или используете это в определенном контексте, вы переходите к реализации.Теперь, в идеале, представление не знает о том, как оно реализуется, и, конечно, не будет знать об именованных регионах в командной консоли.Итак, размещение представлений в Regions внутри модуля - нет-нет.

Чтобы обойти это, я решил делегировать эту ответственность стороннему компоненту, LayoutManager.LayoutManager находится между оболочкой и модулем и определяет «что и куда».Это конкретная реализация, которая действительно определяет реализацию.И представление Shell, и модуль остаются общими.

Взгляните на: http://rgramann.blogspot.com/2009/08/layout-manager-for-prism-v2.html

, что может дать вам некоторые идеи по этой проблеме.

Надеюсь, это поможет.

...