gpt4 book ai didi

c# - 显示模态对话框并获取结果

转载 作者:行者123 更新时间:2023-11-30 16:06:06 27 4
gpt4 key购买 nike

我有一个静态的 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();
}

我的 View 模型引发了一个事件并且 View 订阅了它。在 View 的事件处理程序中,它调用 WindowService.ShowNewWindow(this,The type here)。这很好用。
我的模式对话框创建方法也将以类似的方式工作。唯一的区别是信息将返回到 View (在事件处理程序处),因此 View 必须显式地在代码中将该信息传递给 View 模型。这违反了 mvvm 模式,我不知道如何让 View 模型在事件引发后等待 View 返回值。
有更好的方法吗?

最佳答案

啊,这栗子。

关于如何实现这一点有许多不同的变体,但这是我的两分钱。

这里的主要想法是确保您的ViewView Model 不了解对方,因此您的View 不应该订阅到您的 View Model 中的事件,并且您的 View Model 不应直接调用您的服务并提供 View Type


不要使用事件,而是使用命令

我的建议是使用 ICommand 实现而不是依赖于静态服务类,因为您的类将始终依赖于此服务,并且一旦您发送查看 Type 到此服务,然后 MVVM 模式丢失。

因此,首先,我们需要某种命令来打开给定 Type 的窗口,这是我想出的:

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 并指定接受 Type 的实现,它表示我们要打开的所需 View。请注意,我已将一个方法标记为 virtual,稍后我将解释该部分。

下面是我们如何在 View Model 中使用此命令:

public class MainWindowViewModel
{
public OpenWindowCommand OpenWindowCommand { get; private set; }

public MainWindowViewModel()
{
OpenWindowCommand = new OpenWindowCommand();
}

...
}

现在我们已经创建了命令,我们只需要绑定(bind)一个 Button 到它:

<Button Content="Open Window"
Command="{Binding OpenWindowCommand}"
CommandParameter="{x:Type local:MyWindow}"/>

这里要注意的一件事是我使用x:Type 作为CommandParameter,这是Window,当此命令被执行。


但是对话呢?

我们上面实现的只是需求的一半,我们现在需要一些东西来显示对话框并将结果输出到我们的View Model,这并没有那么棘手,因为我们在现有的 OpenWindowCommand 中已经有了我们需要的大部分内容。

首先,我们需要创建命令:

public class ShowDialogCommand : OpenWindowCommand
{
private Action _PreOpenDialogAction;
private Action<bool?> _PostOpenDialogAction;

public ShowDialogCommand(Action<bool?> postDialogAction)
{
if (postDialogAction == null)
throw new ArgumentNullException("postDialogAction");

_PostOpenDialogAction = postDialogAction;
}

public ShowDialogCommand(Action<bool?> postDialogAction, Action preDialogAction)
: this(postDialogAction)
{
if (preDialogAction == null)
throw new ArgumentNullException("preDialogAction");

_PreOpenDialogAction = preDialogAction;
}

protected override void OpenWindow(System.Windows.Window wnd)
{
//If there is a pre dialog action then invoke that.
if (_PreOpenDialogAction != null)
_PreOpenDialogAction();

//Show the dialog
bool? result = wnd.ShowDialog();

//Invoke the post open dialog action.
_PostOpenDialogAction(result);
}
}

我们通过继承 OpenWindowCommand 并使用它的实现来使用它,而不必将其全部复制到我们的新类中。该命令采用 Action,它是对 View Model 中方法的引用,您可以选择在之前 定义操作>在(或两者)之后显示一个对话框。

下一步是更改我们的 View 模型,以便它创建这个新命令:

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

好了,一切都是松耦合的,这里唯一真正的依赖是你的 View Model 依赖于你的 ICommand 类。


最后的话

我创建的 ICommand 类充当 ViewView Model 之间的 Controller ,以确保它们不知道彼此,并保持 MVVM 模式的强制执行。

就像我在本回答开头所说的那样,有很多方法可以实现这一点,但是我希望您现在开明一点。

关于c# - 显示模态对话框并获取结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32739791/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com