Никогда не думал, что увижу, что меня цитируют в вопросе.
Я некоторое время обдумывал этот вопрос и принял довольно прагматичное решение для своей кодовой базы:
В моей кодовой базе ViewModel вызывается, когда происходят какие-то действия, и я хотел, чтобы так и оставалось. Кроме того, я не хочу, чтобы ViewModel управлял представлениями.
Что я сделал?
Я добавил контроллер для навигации:
public interface INavigation
{
void NewContent(ViewModel viewmodel);
void NewWindow(ViewModel viewmodel);
}
Этот контроллер содержит два действия: NewContent () отображает новое содержимое в текущем окне, NewWindow () создает новое окно, заполняет его содержимым и показывает его.
Конечно, мои viewmodels не имеют ни малейшего представления, какой вид показать. Но они знают, какую модель представления они хотят показать, поэтому в соответствии с вашим примером при выполнении DeleteCommand он вызвал бы функцию службы навигации NewWindow (new ValidateCustomerDeletedViewModel ()) , чтобы показать окно, в котором указано, что клиент имеет был удален »(избыточно для этого простого ящика сообщений, но было бы легко иметь специальную функцию навигатора для простых ящиков сообщений).
Как viewmodel получает навигационный сервис?
Мой класс viewmodel имеет свойство для контроллера навигации:
public class ViewModel
{
public INavigation Navigator { get; set; }
[...]
}
Когда модель представления присоединяется к окну (или к чему-либо, отображающему представление), окно устанавливает свойство Navigator, поэтому модель представления может вызывать его.
Как навигатор создает представление для модели вида?
У вас может быть простой список, представление которого создавать, для какой модели представления, в моем случае я могу использовать простое отражение, поскольку имена совпадают:
public static FrameworkElement CreateView(ViewModel viewmodel)
{
Type vmt = viewmodel.GetType();
// big bad dirty hack to get the name of the view, but it works *cough*
Type vt = Type.GetType(vmt.AssemblyQualifiedName.Replace("ViewModel, ", "View, "));
return (FrameworkElement)Activator.CreateInstance(vt, viewmodel);
}
Конечно, представлению нужен конструктор, принимающий модель представления в качестве параметра:
public partial class ValidateCustomerDeletedView : UserControl
{
public ValidateCustomerDeletedView(ValidateCustomerDeletedViewModel dac)
{
InitializeComponent();
this.DataContext = dac;
}
}
Как выглядит мое окно?
Простой: мое главное окно реализует интерфейс INavigation и показывает стартовую страницу при создании. Убедитесь сами:
public partial class MainWindow : Window, INavigation
{
public MainWindow()
{
InitializeComponent();
NewContent(new StartPageViewModel());
}
public MainWindow(ViewModel newcontrol)
{
InitializeComponent();
NewContent(newcontrol);
}
#region INavigation Member
public void NewContent(ViewModel newviewmodel)
{
newviewmodel.Navigator = this;
FrameworkElement ui = App.CreateView(newviewmodel);
this.Content = ui;
this.DataContext = ui.DataContext;
}
public void NewWindow(ViewModel viewModel)
{
MainWindow newwindow = new MainWindow(viewModel);
newwindow.Show();
}
#endregion
}
(Это одинаково хорошо работает с окном NavigationWindow и переносом представления на страницу)
Конечно, это можно проверить, так как навигационный контроллер может быть легко смоделирован.
Я не совсем уверен, что это идеальное решение, но сейчас оно прекрасно работает для меня. Любые идеи и комментарии приветствуются!