2015-10-05 3 views
0

У меня есть связанный с дизайном вопрос, специфичный для WPF и Prism. Я работаю над приложением правил, где мне нужно отображать различные типы правил (Модели) иерархическим способом в элементе управления TreeView. Я завернул каждый экземпляр модели в их соответствующую ViewModel и привязал ее к TreeView. Ниже я попытался изобразить иерархию только для того, чтобы подчеркнуть то, что может быть несколько ViewModels одного типа и на основе их выбора мне нужно соответствующим образом отобразить соответствующий View.Перейдите к просмотру, введя конкретную ViewModel в WPF Prism

Правила

--- группа (экземпляр GroupViewModel 1)

------ Х (XViewModel экземпляр 1)

--------- Z (ZViewModel экземпляр 1)

------ Х (XViewModel экземпляр 2)

--- группа (экземпляр GroupViewModel 2)

------ У (YViewModel экземпляр 1)

------ Z (ZViewModel экземпляр 2)

--------- экземпляр Х (XViewModel 3)

Проблема:

мне нужен механизм сначала получить выбранный элемент из TreeView, а затем перейти к View ViewModel, используя Uri (иметь слабосвязанности) на основе выбора элементов дерева и кормить/впрыснуть выбранный ViewModel в представлении. Нужный пример кода для получения выбранного ViewModel, перейдите к View вместе с вводом ViewModel?

Цель:

Я ищу некоторую лучшую практику справиться с этой ситуацией в WPF с Prism для поддержания слабосвязанности.

Важное примечание: TreeView показывается в одном регионе, а контент является частью другого региона, и я использую контейнер MEF DI.

ответ

1

1) Предполагая, что «Выполнение» - это своего рода бизнес-логика, тогда кажется, что это действительно справедливо для этого в классе модели. То же с валидацией. На самом деле это, вероятно, данное, поскольку вы хотите иметь всю свою бизнес-логику и валидацию в одном месте. Затем эта модель может (потенциально) быть повторно использована в будущем, скажем, если вы решите разработать веб-систему поверх существующих моделей. На самом деле я once asked a similar question к вам некоторое время назад.

Лично я думаю, что хорошо иметь класс «богатых» моделей, в том числе свойства, которые реализуют INotifyPropertyChanged, что делает его «привязывающим». Это вполне приемлемо, так как этот интерфейс не живет в пространстве имен фреймворка, связанного с пользовательским интерфейсом (System.ComponentModel). Я даже зашел так далеко, чтобы включить удобные свойства ICommand в своих моделях, хотя это зависит от того, какая часть «пуриста» вы, размывая линии между определением модели и модели представления. Это приводит к вашему второму вопросу - имея такую ​​модель, она может быть привязана непосредственно к представлению, обнажая модель через свойство VM.

Многие разработчики WPF, похоже, написали классы VM, которые в основном представляют собой зеркальные отображения классов моделей (со всеми кодами отображения/вывода), но включая такие вещи, как свойства INPC и ICommands. Много накладных расходов, которые я (лично) никогда не видел. Опять же, кажется, что есть два «лагеря» относительно того, как вы используете модели и виртуальные машины, возможно, в некоторой степени в зависимости от того, как должно быть «многоуровневое» ваше приложение. Многие из них сводятся к личным предпочтениям, и, как и многие проблемы с разработчиками, я не думаю, что есть правильный или неправильный подход.

Что касается 3), вы хотите щелкнуть элемент в TreeView, в результате чего представление будет отображаться в другом месте приложения? Я предполагаю, что вы используете инфраструктуру инъекций зависимостей? AFAIK менеджер региона Prism требует этого, и я не знаю, как использовать менеджер региона без рамки DI.

Вам в первую очередь необходимо определить область, в которой для отображения этой точки зрения, например: -

<ContentControl Regions:RegionManager.RegionName="MyRegionName" /> 

Чтобы отобразить вид в регионе вы используете Prism область менеджер: -

_regionManager.RequestNavigate("MyViewName", "MyRegionName"); 

Имя вида присваивается при регистрации вашего представления с помощью рамки DI, например как это делается в Замке Виндзор: -

Container.Register(Component.For<MyView>().ImplementedBy<MyView>().LifeStyle.Transient.Named("MyViewName")); 

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

Edit (на основе О.П. редактирования):

Вы не сказали ли регион в ту же точку зрения, как TreeView. Если это так, то вы, вероятно, сможете достичь этого без навигации по Призмам. «Основной» VM (в отношении зрения TreeView в) может выставить выбранное правило VM, которые можно привязать к ContentControl (как INotifyPropertyChanged собственность, конечно!):

<ContentControl Content="{Binding SelectedRule}" /> 

Тогда это просто случай создание DataTemplates для правила виртуальных машин: -

<DataTemplate DateType="{x:Type XRuleViewModel}"> 
    ... XAML ... 
</DataTemplate> 

по мере изменения выбора TreeView, то ContentControl будет связываться с соответствующим правилом VM, и соответствующий DataTemplate будет оказывать необходимое содержание.

Если регион is в отдельном окне, то вам необходимо использовать навигацию Prism. Проблема здесь в том, что вам нужно имя представления для навигации, но ваша «основная» (TreeView) VM не знает представления, а только виртуальные машины правила. Простой вариант может состоять в том, чтобы иметь свойство на ваших виртуальных виртуальных машинах, которое предоставляет соответствующее имя вида. Если вы более пурист и хотите сохранить это знание вне виртуальных машин, вы можете реализовать механизм, в котором вы регистрируете все свои виртуальные машины с именами соответствующих им представлений (например, во время запуска приложения). Это может быть так же просто, как Dictionary. Когда в TreeView выбрано правило VM, вам просто нужно найти соответствующее имя представления для использования в вызове RequestNavigate().

+0

Спасибо за ваш ответ, но я до сих пор не могу получить точку нет. 3. Я знаю о регионах и просматриваю View, используя ту же технику, но проблема в том, что я могу дать указание моему представлению отобразить определенный ViewModel на основе выбранного элемента TreeView. Да, я использую MEF DI в Prism. –

+0

@FSX, чтобы вы могли отображать определенное представление в зависимости от того, какой элемент дерева вы нажимаете? И где будет отображаться этот вид - как контент в том же окне, что и дерево, или что-то еще? –

+0

См. Мой отредактированный вопрос выше с более подробной информацией и разъяснениями –

1

@ Андрюд находится на правильном пути. Во-первых, нет необходимости обертывать ваши модели в ViewModel, если ваша архитектура не требует этого. Который, я могу догадаться, это не так.Самый простой способ выполнить эту задачу - использовать InvokeCommandAction в ответ на выбранное событие с измененным элементом. Затем выполните команду, которая перейдет к вашему желаемому виду. Используйте выбранную tem в качестве параметра, чтобы определить, какой вид вы ищете. Когда вы перемещаетесь, вы также можете передать выбранный элемент в качестве параметра с помощью NavigationParameters и использовать INavigationAware для цели, чтобы получить этот параметр в методе OnNavigatedTo.