从 ViewModel 创建 window 的最佳方法是什么?
What is the best way to create window from ViewModel?
正如我的标题所暗示的,我想知道在 MVVM 模式中从 ViewModel 创建 window 的最佳和最简单的方法是什么。
i want to know what is the best and simplest method to create window from ViewModel in MVVM pattern
“最好”、“最简单”是非常主观的概念。
对于某些人来说,一个简单的实现可能被某些人认为是困难的。
这个题目很大,要详细回答这样的问题,你得写一本厚厚的教科书。
因此,简而言之,一般概念和可能实现的示例。
从 ViewModel 的角度来看,它无法“知道”Window 是什么。所以问这个问题“VM 应该如何创建 Window?” - 这是不正确的。
问题应该这样问:“VM如何调用外部对话?”。
如何为 VM 实现此对话框(WPF Window、表单或控制台输入)并不重要。
实际上,对话是对方法的委托,return 是对话结果。
在最简单的情况下,对话框的结果只是一个布尔值(成功/失败)。
假设 OpenFileDialog.ShowDialog returns Nullable <bool>
.
在更复杂的情况下,枚举是 returned。 MessageBox 示例。
你需要什么样的对话结果取决于你的任务条件。
假设这是一个元素编辑对话框,那么它在参数中接收到一个要编辑的元素,它可以 return bool: true - 编辑完成,其结果需要保存,false -编辑取消。
获取 ViewModel 委托,通常是在其创建时。
这称为依赖注入。
依赖注入的典型位置是 App.
一个例子会link到你之前的话题
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 资源中设置它很方便。
为此,让我们制作一个简单的容器-class:
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;
}
}
在 Main Window 中,我们设置从定位器获取 DataContext:
<Window ---------
-------------
DataContext="{Binding MainVM, Source={StaticResource locator}}">
正如我的标题所暗示的,我想知道在 MVVM 模式中从 ViewModel 创建 window 的最佳和最简单的方法是什么。
i want to know what is the best and simplest method to create window from ViewModel in MVVM pattern
“最好”、“最简单”是非常主观的概念。
对于某些人来说,一个简单的实现可能被某些人认为是困难的。
这个题目很大,要详细回答这样的问题,你得写一本厚厚的教科书。
因此,简而言之,一般概念和可能实现的示例。
从 ViewModel 的角度来看,它无法“知道”Window 是什么。所以问这个问题“VM 应该如何创建 Window?” - 这是不正确的。
问题应该这样问:“VM如何调用外部对话?”。
如何为 VM 实现此对话框(WPF Window、表单或控制台输入)并不重要。
实际上,对话是对方法的委托,return 是对话结果。
在最简单的情况下,对话框的结果只是一个布尔值(成功/失败)。
假设 OpenFileDialog.ShowDialog returns Nullable <bool>
.
在更复杂的情况下,枚举是 returned。 MessageBox 示例。
你需要什么样的对话结果取决于你的任务条件。
假设这是一个元素编辑对话框,那么它在参数中接收到一个要编辑的元素,它可以 return bool: true - 编辑完成,其结果需要保存,false -编辑取消。
获取 ViewModel 委托,通常是在其创建时。
这称为依赖注入。
依赖注入的典型位置是 App.
一个例子会link到你之前的话题
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 资源中设置它很方便。 为此,让我们制作一个简单的容器-class:
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;
}
}
在 Main Window 中,我们设置从定位器获取 DataContext:
<Window ---------
-------------
DataContext="{Binding MainVM, Source={StaticResource locator}}">