Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 显示模式对话框并获取结果_C#_Wpf_Mvvm_Modal Dialog - Fatal编程技术网

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}"/>