Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.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# 关闭所有子WPF窗口并终止等待代码_C#_Wpf_Mvvm_Modal Dialog_Async Await - Fatal编程技术网

C# 关闭所有子WPF窗口并终止等待代码

C# 关闭所有子WPF窗口并终止等待代码,c#,wpf,mvvm,modal-dialog,async-await,C#,Wpf,Mvvm,Modal Dialog,Async Await,我正在尝试实现一个系统,用于关闭WPF应用程序中的所有模式和非模式窗口(主应用程序窗口除外)。当这些窗口关闭时,应放弃等待对话框结果的任何代码 到目前为止,我考虑/尝试了两种策略: 关闭并重新启动应用程序 关闭所有窗口并依靠任务取消异常放弃所有等待对话框结果的代码。(它冒泡到应用程序级别,然后被处理。) 第一个解决方案肯定会让应用程序关闭,并足以自动注销,但我对在等待的对话框关闭后继续执行的代码感到非常不舒服。有没有一个好方法来停止代码的执行 第二种解决方案工作得相对较好(调用代码被中止),但有

我正在尝试实现一个系统,用于关闭WPF应用程序中的所有模式和非模式窗口(主应用程序窗口除外)。当这些窗口关闭时,应放弃等待对话框结果的任何代码

到目前为止,我考虑/尝试了两种策略:

  • 关闭并重新启动应用程序
  • 关闭所有窗口并依靠任务取消异常放弃所有等待对话框结果的代码。(它冒泡到应用程序级别,然后被处理。)
  • 第一个解决方案肯定会让应用程序关闭,并足以自动注销,但我对在等待的对话框关闭后继续执行的代码感到非常不舒服。有没有一个好方法来停止代码的执行

    第二种解决方案工作得相对较好(调用代码被中止),但有一个关键缺陷:有时,模式窗口和非模式窗口的某些组合快速连续关闭会导致应用程序在
    ShowDialog
    调用时锁定。(至少,当您暂停执行时,它就结束了。)这很奇怪,因为断点清楚地表明,
    Closed
    事件正在我打算关闭的所有窗口上引发。最终用户看到的结果是一个登录屏幕,该屏幕无法单击,但可以通过选项卡进入。真奇怪!尝试以不同优先级调度呼叫失败,但任务延迟100毫秒可能就成功了。(但这不是一个真正的解决方案。)

    如果每个打开的弹出窗口都在后台等待一个
    TaskCompletionSource
    ,并且在完成TCS后,尝试使用调度程序在其自身上调用
    Close
    ,为什么即使在看到引发
    Closed
    事件后,仍有一个(或多个)对话框在
    ShowDialog
    上阻塞?有没有办法正确地将这些调用分派到
    Close
    以便它们成功完成?我是否需要特别说明车窗关闭的顺序

    一些伪代码-C#-混合示例:

    class PopupService
    {
        async Task<bool> ShowModalAsync(...)
        {
            create TaskCompletionSource, publish event with TCS in payload
            await and return the TCS result
        }
    
        void ShowModal(...)
        {
            // method exists for historical purposes. code calling this should
            // probably be made async-aware rather than relying on the blocking
            // behavior of Window.ShowDialog
            create TaskCompletionSource, publish event with TCS in payload
            rethrow exceptions that are set on the Task after completion but do not await
        }
    
        void CloseAllWindows(...)
        {
            for every known TaskCompletionSource driving a popup interaction
                tcs.TrySetCanceled()
        }
    }
    
    class MainWindow : Window
    {
        void ShowModalEventHandler(...)
        {
            create a new PopupWindow and set the owner, content, etc.
            var window = new PopupWindow(...) { ... };
            ...
            window.ShowDialog();
        }
    }
    
    class PopupWindow : Window
    {
        void LoadedEventHandler(...)
        {
            ...
            Task.Run(async () =>
            {
                try
                    await the task completion source
                finally
                    Dispatcher.Invoke(Close, DispatcherPriority.Send);
            });
    
            register closing event handlers
            ...
        }
    
        void ClosedEventHandler(...)
        {
            if(we should do something with the TCS)
                try set the TCS result so the popup service caller can continue
        }
    }
    
    class-PopupService
    {
    异步任务ShowModalAsync(…)
    {
    创建TaskCompletionSource,使用负载中的TCS发布事件
    等待并返回TCS结果
    }
    void showmodel(…)
    {
    //方法是出于历史目的而存在的。调用此方法的代码应
    //可能是异步感知的,而不是依赖于阻塞
    //Window.ShowDialog的行为
    创建TaskCompletionSource,使用负载中的TCS发布事件
    重新显示任务完成后设置但不等待的异常
    }
    无效关闭所有窗口(…)
    {
    对于驱动弹出式交互的每个已知TaskCompletionSource
    tcs.TrySetCanceled()
    }
    }
    类主窗口:窗口
    {
    void ShowModalEventHandler(…)
    {
    创建新的PopupWindow并设置所有者、内容等。
    var窗口=新的PopupWindow(…){…};
    ...
    ShowDialog();
    }
    }
    类弹出窗口:窗口
    {
    无效加载的排气阀(…)
    {
    ...
    Task.Run(异步()=>
    {
    尝试
    等待任务完成源
    最后
    调用(关闭,DispatcherPriority.Send);
    });
    注册关闭事件处理程序
    ...
    }
    void ClosedEventHandler(…)
    {
    如果(我们应该对TCS采取措施)
    尝试设置TCS结果,以便弹出服务调用方可以继续
    }
    }
    
    我不确定这是否能解决您的问题,但就我而言,我创建了扩展方法来帮助混合异步代码和窗口生命周期管理。例如,您可以创建一个ShowDialogAsync(),它返回将在窗口实际关闭时完成的任务。如果您请求取消,还可以提供CancellationToken来自动关闭对话框

    公共静态类窗口扩展
    {
    公共静态任务ShowDialogAsync(此窗口,CancellationToken CancellationToken=new CancellationToken())
    {
    var completionSource=new TaskCompletionSource();
    window.Dispatcher.BeginInvoke(新操作(()=>
    {
    var result=window.ShowDialog();
    //对话框关闭时,设置结果以完成返回的任务。如果任务已取消,则将放弃该任务。
    completionSource.TrySetResult(结果);
    }));
    如果(cancellationToken.canbecancelled)
    {
    //请求取消时收到通知,以便我们可以关闭窗口并取消返回的任务
    cancellationToken.Register(()=>window.Dispatcher.BeginInvoke(新操作(()=>
    {
    completionSource.TrySetCanceled();
    window.Close();
    })));
    }
    返回completionSource.Task;
    }
    }
    
    在UI代码中,可以使用如下所示的ShowDialogAsync()方法。如您所见,当任务被取消时,对话框将关闭,并引发OperationCanceledException异常以停止代码流

    private async void按钮\u单击(对象发送方,路由目标)
    {
    尝试
    {
    YourDialog=新建YourDialog();
    CancellationTokenSource=新的CancellationTokenSource(TimeSpan.FromSeconds(3));
    wait dialog.ShowDialogAsync(source.Token);
    }
    捕捉(操作取消例外)
    {
    MessageBox.Show(“操作已取消”);
    }
    }
    
    使用
    窗口。ShowDialog
    可创建嵌套的
    Dispather
    消息循环。使用
    await
    ,可以在该内部循环上“跳转”并继续执行
    async
    方法,例如:

    var dialogTask=window.ShowDialogAsync()
    
    foreach(Window item in App.Current.Windows)
                {
                    if(item!=this)
                        item.Close();
                }