Я изучаю использование MVVM и в то время как я понимаю это по большей части, существует одна вещь, я не могу получить голову вокруг.
Предположите, что у меня есть комбинация Представления и ViewModel, которые показывают список foobars. Когда пользователь выбирает foobar в списке и нажимает кнопку редактирования, я хочу, чтобы foobar был показан в раскрывающемся диалоговом окне, таким образом, это может быть отредактировано. Это диалоговое окно (представление) будет иметь свой собственный связанный ViewModel.
Я понимаю, что кнопка может быть связана с командой в списке ViewModel, но отсюда как я инстанцирую foobar редактора?
1) Я должен передать сообщение обратно Представлению, которое откроет диалоговое окно? Если так, разве это не побеждает цель наличия команды?
2) Как foobar становится переданным в ViewModel для редактора? Если это его конструктором, разве это не мешает объявлять ViewModel в XAML?
Я чувствую, что это - последняя часть загадки, которая препятствует тому, чтобы я использовал MVVM, и я действительно хотел бы получить хорошее разъединенное решение этого.
Матовое спасибо
В этой статье из codeproject показан элемент управления диалогового окна WPF, который делает именно то, что вам нужно. Причина, по которой эта реализация необходима, заключается в том, что вы не можете поместить Window внутри визуального дерева любого другого элемента управления. Это означает, что из коробки WPF не позволяет создавать диалог внутри окна. Таким образом, в приведенной выше статье создается подкласс ContentControl, который создает окно.
В любом случае, вы помещаете это в свое представление FooBarList.
<dialog:Dialog Content="{Binding Path=DialogViewModel}" />
Убедитесь, что у вас есть что-то подобное в словаре ресурсов где-то:
<Style TargetType="{x:Type dialog:Dialog}">
<Style.Triggers>
<Trigger Property="HasContent" Value="True">
<Setter Property="Showing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
и просто напишите что-то вроде этого (для работы WPF вам необходимо реализовать INotifyPropertyChanged):
public Class FooBarListViewModel
{
IList<FooBar> FooBarList {get;set;}
FooBar SelectedFooBar {get;set;}
ViewModelBase DialogViewModel {get;set;}
public EditFooBar(object param)
{
DialogViewModel = FooBar;
}
}
Чтобы связать View для редактирования FooBar с ViewModel FooBar, просто сделайте что-нибудь вроде этого (желательно в Application.Ресурсы, чтобы он был глобальным)
<DataTemplate DataType={x:Type vm:FooBarViewModel}>
<vw:FooBarView/>
</DataTemplate>
(Или, необязательно: используйте IValueConverter для преобразования, чтобы получить представление из ViewModel , как показано в этом сообщении )
И тогда все готово. Может показаться, что это много, но это действительно сильно освобождает.
Я бы, возможно, сделал это следующим образом:
Необходимость в клоне возникает из-за того, что пользователь не хочет видеть изменения в списке foobar, пока он не примет изменения в диалоговом окне редактирования. Однако, если онлайн-редактирование в порядке, клон не нужен.
Изменения распространяются автоматически.
PS: хотя я сторонник MVVM, я не уверен, что мое решение является ортодоксальным с точки зрения чистого MVVM.
Чего не хватает, так это контроллера, который отвечает за рабочий процесс ViewModels. Контроллер создает ViewModels и передает необходимые данные между ViewModels.
Проект WPF Application Framework (WAF) содержит примеры приложений, которые показывают, как это может работать.