当用户使用MVVM单击关闭按钮时,如何取消WPF对话框中的等待



我有一个应用程序,它要求用户在对话框中输入SQL连接信息。当用户单击"连接"按钮时,我将await SqlConnection.OpenAsync()的结果与提供的凭据进行比较,以便在关闭对话框之前测试它们是否有效。我还禁用了"连接"按钮以避免重复尝试。当凭据正确时,它几乎会立即返回,但如果凭据不正确,则可能需要长达30秒的时间才能返回。取消按钮可以使用CancellationToken取消请求并关闭对话框。

问题是,用户仍然可以单击对话框上的窗口关闭按钮来关闭它。我的视图模型没有收到通知,但表单仍然关闭。大约30秒后,连接尝试返回错误信息,并显示一个消息框。

当表单以这种方式关闭时,是否有一种好的、MVVM友好的方法来取消与我的CancelationToken的连接尝试?我知道我可以在对话框的代码后面使用来装配一些东西,但我希望避免从那里引用视图模型。

根据MVVM基础设施的使用情况,您可以在Window.Closing上使用类似MVVM Light的EventToCommand的东西。您可以将此事件绑定到已附加到按钮的取消命令。

请参阅MVVM Light:在没有Blend的XAML中添加EventToCommand,更简单的方法或片段?想办法做到这一点。

尝试等待SqlConnection的结果。OpenAsync()并传入取消令牌。

您可以为此编写一个扩展方法。

因此,您有一个类(让我们称之为WindowExtensions),其中定义了附加属性。

internal class WindowExtensions
{
    public static readonly DependencyProperty WindowClosingCommandProperty = DependencyProperty.RegisterAttached(
        "WindowClosingCommand", typeof (ICommand), typeof (WindowExtensions), new PropertyMetadata(null, OnWindowClosingCommandChanged));
    private static void OnWindowClosingCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Window window = d as Window;
        if (window == null)
            return;
        if (e.NewValue != null)
        {
            window.Closing += WindowOnClosing;
        }
    }
    private static void WindowOnClosing(object sender, CancelEventArgs e)
    {
        Window window = sender as Window;
        if (window == null)
            return;
        ICommand windowClosingCommand = GetWindowClosingCommand(window);
        windowClosingCommand.Execute(e);
    }
    public static void SetWindowClosingCommand(DependencyObject element, ICommand value)
    {
        element.SetValue(WindowClosingCommandProperty, value);
    }
    public static ICommand GetWindowClosingCommand(DependencyObject element)
    {
        return (ICommand) element.GetValue(WindowClosingCommandProperty);
    }
}

在Window元素上的XAML中,您可以将附加的属性映射到ViewModel中的ICommand属性,如:

nameSpaceOfWindowExtensions:WindowExtensions.WindowClosingCommand="{Binding WindowClosingCommand}"

在您的ViewModel中,您有一个ICommand-属性,您可以在其中处理它。类似于:

private ICommand windowClosingCommand;
public ICommand WindowClosingCommand
{
    get { return windowClosingCommand ?? (windowClosingCommand = new RelayCommand(OnWindowClosing)); }
}
private void OnWindowClosing(object parameter)
{
    CancelEventArgs cancelEventArgs = parameter as CancelEventArgs;
    if (cancelEventArgs != null)
    {
        // If you want to cancel the closing of the window you can call the following:
        //cancelEventArgs.Cancel = true;
    }
}

如果您在ViewModel中不需要CancelEventArgs,只需修改附加属性中的以下行:

windowClosingCommand.Execute(e);

windowClosingCommand.Execute(null);

最新更新