【发布时间】:2021-08-30 06:59:37
【问题描述】:
正如我的标题所暗示的,我想知道在 MVVM 模式中从 ViewModel 创建窗口的最佳和最简单的方法是什么。
【问题讨论】:
-
创建一个用于注入视图模型的窗口服务:stackoverflow.com/questions/47352870/…
正如我的标题所暗示的,我想知道在 MVVM 模式中从 ViewModel 创建窗口的最佳和最简单的方法是什么。
【问题讨论】:
我想知道在 MVVM 模式中从 ViewModel 创建窗口的最佳和最简单的方法是什么
“最好的”、“最简单的”是非常主观的概念。
对于某些人来说,一个简单的实现可能会被某些人认为是困难的。
这个话题很大,要详细回答这样的问题,你需要写一本厚厚的教科书。
因此,简而言之,一般概念和可能实现的示例。
从 ViewModel 的角度来看,它无法“知道”什么是 Window。所以问“虚拟机应该如何创建一个窗口?”这个问题。 - 这是不正确的。
应该这样问这个问题:“VM 如何调用外部对话?”。
如何为 VM 实现此对话框(WPF 窗口、表单或控制台输入)并不重要。
实际上,对话框是返回对话框结果的方法的委托。
在最简单的情况下,dialog 的结果只是一个 bool(成功/失败)。
假设 OpenFileDialog.ShowDialog 返回Nullable <bool>。
在更复杂的情况下,会返回一个枚举。示例消息框。
您需要什么样的对话结果取决于您的任务条件。
假设这是一个元素编辑对话框,那么它在其参数中接收到一个要编辑的元素,它可以返回bool:true - 编辑完成并需要保存结果,false - 取消编辑。
获取 ViewModel 委托,通常在其创建时。
这称为依赖注入。
一个典型的依赖注入的地方就是App。
一个示例将链接到您之前的主题WPF MVVM binding command to Datacontext inside Datagrid
using System;
using System.Collections.ObjectModel;
namespace MoldsApp
{
public class MainWindowViewModel
{
//A collection-property of type ObservableCollection is best implemented as «ReadOnly».
public ObservableCollection<Molds> AllMolds { get; }
private readonly Func<Molds, bool> editDialog;
// Constructor receiving dialog delegate
public MainWindowViewModel(Func<Molds, bool> editDialog)
{
this.editDialog = editDialog;
}
private LamdaCommand _editCommand;
public LamdaCommand EditCommand => _editCommand
?? (_editCommand = new LamdaCommand(EditExecute, EditCanExecute));
private bool EditCanExecute(object parameter)
=> parameter is Molds;
private void EditExecute(object parameter)
{
Molds molds = (Molds)parameter;
// At this point, there should be element preprocessing code.
// Let's say copying for the possibility of canceling the result of editing.
Molds moldsCopy = molds.Copy();
// Calling a dialog and getting its result
var result = editDialog(moldsCopy);
if (result)
{
// Saving the result.
// And changing the item to match the edited copy.
Save(moldsCopy);
molds.CopyValuesFrom(moldsCopy);
}
}
private void Save(Molds moldsCopy)
{
throw new NotImplementedException();
}
}
}
MainWindowViewModel 实例将在 App. 为了让Window把它拿到它的DataContext中,在App资源中设置它比较方便。 为此,让我们创建一个简单的容器类:
public class Locator
{
public MainWindowViewModel MainVM { get; set; }
}
<Application ----------
----------
StartupUri="MainWindow.xaml"
Startup="OnStartup">
<Application.Resources>
<moldsapp:Locator x:Key="locator"/>
</Application.Resources>
</Application>
现在,在 App Code Behind 中,我们初始化所有这些:
public partial class App : Application
{
private void OnStartup(object sender, StartupEventArgs e)
{
Locator locator = (Locator) Resources["locator"];
locator.MainVM = new MainWindowViewModel(MoldsEditHandler);
}
private static bool MoldsEditHandler(Molds molds)
{
AddEditWindow window = new AddEditWindow()
{
DataContext = new AddEditWindowViewModel(molds)
};
var result = window.ShowDialog();
return result == true;
}
}
在主窗口中,我们设置从定位器获取 DataContext:
<Window ---------
-------------
DataContext="{Binding MainVM, Source={StaticResource locator}}">
【讨论】: