C# 显示模式对话框并获取结果
我有一个静态的C# 显示模式对话框并获取结果,c#,wpf,mvvm,modal-dialog,C#,Wpf,Mvvm,Modal Dialog,我有一个静态的WindowService类,它可以帮助我创建新的窗口和模式对话框。 到目前为止,我得到的是: /// <summary> /// Opens a new window of type <paramref name="newWindowType"/> and closes the <paramref name="oldWindow"/> /// </summary> /// <param name="oldWindow">
WindowService
类,它可以帮助我创建新的窗口和模式对话框。
到目前为止,我得到的是:
/// <summary>
/// Opens a new window of type <paramref name="newWindowType"/> and closes the <paramref name="oldWindow"/>
/// </summary>
/// <param name="oldWindow">The window which should be closed (Usually the current open window)</param>
/// <param name="newWindowType">The type of the new window to open</param>
public static void ShowNewWindow(Window oldWindow, Type newWindowType)
{
((Window)Activator.CreateInstance(newWindowType)).Show();
oldWindow.Close();
}
//
///打开类型为的新窗口并关闭
///
///应关闭的窗口(通常为当前打开的窗口)
///要打开的新窗口的类型
公共静态void ShowNewWindow(Window oldWindow,类型newWindowType)
{
((Window)Activator.CreateInstance(newWindowType)).Show();
oldWindow.Close();
}
My viewmodel引发一个事件,并且视图已订阅该事件。在视图中的事件处理程序中,它调用WindowService.ShowNewWindow(此处为类型)
。这很好。我的模态对话框创建方法也将以类似的方式工作。唯一的区别是信息将返回到视图(在事件处理程序处),因此视图必须在代码中显式地将该信息传递给视图模型。这违反了mvvm模式,我不知道如何使viewmodel在引发事件后等待视图返回值。
有没有更好的方法呢?啊,这个老栗子 关于如何实现这一点,有很多不同的方法,但这里是我的两分钱 这里的主要思想是确保您的
视图
和视图模型
彼此不了解,因此您的视图
不应订阅您的视图模型
中的事件,您的视图模型
不应直接调用您的服务并提供视图类型
不要使用事件,而是使用命令 我的建议是使用
ICommand
实现,而不是依赖于静态服务类,因为您的类将始终依赖于此服务,而且只要您将视图Type
发送到此服务,MVVM模式就会丢失
因此,首先,我们需要某种命令来打开给定类型的窗口,下面是我想到的:
public class OpenWindowCommand : ICommand
{
public bool CanExecute(object parameter)
{
TypeInfo p = (TypeInfo)parameter;
return p.BaseType == typeof(Window);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (parameter == null)
throw new ArgumentNullException("TargetWindowType");
//Get the type.
TypeInfo p = (TypeInfo)parameter;
Type t = p.BaseType;
if (p.BaseType != typeof(Window))
throw new InvalidOperationException("parameter is not a Window type");
//Create the window.
Window wnd = Activator.CreateInstance(t) as Window;
OpenWindow(wnd);
}
protected virtual void OpenWindow(Window wnd)
{
wnd.Show();
}
}
该类继承自ICommand
,并指定接受类型的实现,该类型表示希望打开的视图。注意,我已经将一个方法标记为virtual
,稍后我将解释该部分
下面是如何在我们的视图模型中使用此命令:
public class MainWindowViewModel
{
public OpenWindowCommand OpenWindowCommand { get; private set; }
public MainWindowViewModel()
{
OpenWindowCommand = new OpenWindowCommand();
}
...
}
现在我们已经创建了命令,只需将一个按钮绑定到它:
<Button Content="Open Window"
Command="{Binding OpenWindowCommand}"
CommandParameter="{x:Type local:MyWindow}"/>
我们正在利用我们的OpenWindowCommand
,从它继承并使用它的实现,而不必将它全部复制到我们的新类中。该命令执行一个操作
,该操作是对视图模型中方法的引用
,您可以选择在显示对话框之前定义一个,或在对话框之后定义一个(或两者都定义)
下一步是更改我们的视图模型
,以便创建此新命令:
public class MainWindowViewModel
{
public OpenWindowCommand OpenWindowCommand { get; private set; }
public ShowDialogCommand ShowDialogCommand { get; private set; }
public MainWindowViewModel()
{
OpenWindowCommand = new OpenWindowCommand();
ShowDialogCommand = new ShowDialogCommand(PostOpenDialog);
}
public void PreOpenDialog()
{
throw new NotImplementedException();
}
public void PostOpenDialog(bool? dialogResult)
{
throw new NotImplementedException();
}
}
此命令的用法实际上与以前相同,但它只是引用了不同的命令:
<Button Content="Open Window"
Command="{Binding ShowDialogCommand}"
CommandParameter="{x:Type local:MyWindow}"/>
在这里,一切都是松散耦合的,这里唯一真正的依赖是您的视图模型取决于您的ICommand
类
最后几句话
我创建的ICommand
类充当视图
和视图模型
之间的控制器,以确保它们彼此不了解,并保持MVVM模式的强制执行
正如我在回答开始时所说,有很多方法可以实现这一点,但我希望你现在更加开明。我相信你已经把事情复杂化了。您错过了一件重要的事情:唯一的区别是信息将返回到视图(在事件处理程序处),因此视图必须在代码中将该信息显式地传递到视图模型
为什么会这样?因为我正在事件处理程序处调用服务方法。非常感谢。这很有帮助:)但是现在打开新视图时我应该如何关闭视图?您可以使用Application.Current.Windows
或Application.Current.MainWindow
来访问当前显示的窗口。ICommand
类上的一些变体需要处理这些问题。它并不完美,但可以为此任务承担一些技术债务。如果您真的想进一步考虑,请考虑创建一个<代码>自定义控件< /代码>,它可以有一个<代码> WindowToClose < /Cord>依赖性属性,然后您的命令可以使用此属性关闭所需的窗口。同样,您必须进行实验,看看什么最有效。谢谢,我修改了命令,将对象作为命令参数。此对象将具有发送者视图、新视图类型和其他信息,以传递给新视图的构造函数。它工作得很好:)我正在使用您的解决方案,并创建了一个自定义的MarkupExtension
来包含类型、窗口所有者和其他内容,我将其作为CommandParameter
传递。我只是想知道为什么ViewModel决定它是一个窗口还是对话框(通过创建的命令实例)?
<Button Content="Open Window"
Command="{Binding ShowDialogCommand}"
CommandParameter="{x:Type local:MyWindow}"/>