Как реализовать элементы меню, зависящие от текущего выбора, в приложении, подобном WPF MVVM explorer
-
22-09-2019 - |
Вопрос
Я новичок в WPF и MVVM, и я работаю над приложением, использующим оба.Приложение похоже на проводник Windows, поэтому рассмотрим приложение с главным окном с меню (ShellViewModel), древовидным элементом управления (TreeViewModel) и элементом управления списком (ListViewModel).Я хочу реализовать такие пункты меню, как Правка -> Удалить, которые удаляют выбранный в данный момент элемент (который может быть в дереве или в списке).
Я использую RelayCommand Джоша Смита, и привязать menuitem к DeleteItemCommand в ShellViewModel несложно.Похоже, однако, что реализация DeleteItemCommand требует некоторой довольно тесной связи между ShellViewModel и двумя дочерними моделями представления (TreeViewModel и ListViewModel), чтобы отслеживать фокус / выбор и направлять действие соответствующему дочернему элементу для реализации.Мне это кажется неправильным и заставляет меня думать, что я что-то упускаю.
Написание менеджера фокуса и / или менеджера выбора для ведения бухгалтерского учета не кажется слишком сложным, и его можно было бы выполнить без объединения классов вместе.Оконная система уже отслеживает, на каком представлении находится фокус, и кажется, что я бы дублировал код.
В чем я не уверен, так это в том, как бы я перенаправил команду из ShellViewModel либо в ListViewModel, либо в TreeViewModel, чтобы выполнить фактическую работу, не внося беспорядок в код.Когда-нибудь приложение будет расширено, чтобы включать в себя более двух дочерних элементов, и я хочу, чтобы оболочка была как можно более неосведомлена о дочерних элементах, чтобы сделать это расширение как можно более безболезненным.
Рассматриваем некоторые примеры приложений WPF / MVVM (зашифрованный текст Карла Шиффлетта, Демо-версия MVVM Джоша Смита, и т.д.), я не видел никакого кода, который делает это (или я этого не понял).
Независимо от того, считаете ли вы мой подход некорректным или я просто упускаю небольшой нюанс, пожалуйста, поделитесь своими мыслями и помогите мне вернуться в нужное русло.Спасибо!
Решение
Существуют некоторые неотъемлемые проблемы с реализацией MVVM Джоша Смита.Взгляните на сообщение Уорда Белла на эту тему: http://neverindoubtnet.blogspot.com/2010/03/mvvm-josh-smiths-way.html.Возможно, вы захотите взглянуть на некоторые альтернативные фреймворки MVVM, такие как Caliburn, которые используют подход ViewModel first и разрывают эту связь.
Другие советы
RelayCommand - это просто способ получить команду в вашей ViewModel, которая может быть привязана к вашему представлению.
Я думаю, что был бы склонен отказаться от всех различных архитектурных вариаций MVVM и примеров приложений и просто использовать старый добрый OOD.Почему бы не иметь какой-нибудь базовый класс ViewModel (т. Е. DetailsViewModelBase) для TreeViewVm и ListViewVm.Поместите туда DeleteCommand с методами CanDelete и Delete, которые имеют столько реализаций, сколько разделяют подклассы (или абстрактные, если таковых нет), а также SelectedItem .Затем привяжите SelectedItem к элементам управления, аналогичным приведенному ниже xaml:
<ListView AlternationCount="2" MinHeight="250" MaxHeight="400"
ItemsSource="{Binding Projects.View}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedProject, Mode=TwoWay}"
behaviors:SelectionBehavior.DoubleClickCommand="{Binding PickCommand}"
ItemContainerStyle="{StaticResource listingRowStyle}"
>
Привязки клавиш выбираются как SelectedItem и синхронизируются с CurrentItem.
HTH,
Беррил
Я нашел запись в блоге автор: Кент Бугарт, который описывает то, что он называет ActiveAwareCommand.Кажется, это делает то, что я искал, хотя я еще не пробовал.В комментарии к сообщению упоминается IActiveAware от Prism как имеющее аналогичное поведение.