Window Close事件中的Threading.task和Dispatcher.Invoke方法

时间:2014-01-04 07:33:31

标签: c# wpf mvvm task dispatcher

我希望在关闭基于MVVM的WPF应用程序时同步执行一系列操作。

现在我在任务中使用Task和Dispatcher.Invoke来向用户显示消息。

问题是当我在Dispatcher.Invoke函数中使用myfunction方法时,应用程序会卡在那里。我知道当我使用除闭合事件以外的这些功能时,此功能正常工作。

因此在应用程序的Close事件中使用Dispatcher.Invoke方法是否有任何问题。我该如何解决这个问题?

/// <summary>
/// Main window closing
/// </summary>
private void MainWindowClosing(object args)
{
     var task1 = System.Threading.Tasks.Task.Factory.StartNew(() =>
     {
         myfunction();
     }).ContinueWith((cc) => {  });
     task1.Wait();
}

private void myfunction()
{
    //my serries of operation will come here.
    System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
    {
        MessageBox.Show("test");
    }));   
}

3 个答案:

答案 0 :(得分:2)

在此处创建Deadlock 。即使将代码放在按钮点击处理程序中,它也不会起作用。

原因

您正在使用task1.Wait()创建任务并等待任务。因此, UI调度程序正在等待任务完成,然后才能处理任何其他消息。

同时你从任务调用UI调度程序上的一个操作,这个操作太同步了

        App.Current.Dispatcher.Invoke(new Action(() =>
            {
                MessageBox.Show("test");
            })); 

但由于UI调度程序仍在等待任务完成,因此无法同步调用任何方法。因此 DEADLOCK (彼此等待)。

可能的解决方案

如果你想同步调用任务而没有关闭窗口,你可以使用以下步骤来实现:

  1. 首先删除 task1.Wait()。 (不要阻止UI调度程序)
  2. 其次,保持bool以保持已开始关闭事件的计数。
  3. 最后,通过设置e.Cancel = true取消关闭事件,并在完成后从任务本身手动提升关闭事件。
  4. 相关代码:

        bool closeInitiated = false;
        private void poc_Closing(object sender, CancelEventArgs e)
        {
            if (!closeInitiated)
            {
                var task1 = System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    myfunction();
                }).ContinueWith((cc) => { });
                closeInitiated = true;
                e.Cancel = true;
            }
        }
    
        private void myfunction()
        {
            App.Current.Dispatcher.Invoke(new Action(() =>
                {
                    MessageBox.Show("test");
                    Close();
                }));
        } 
    

答案 1 :(得分:0)

我认为问题出在task1.Wait();完成此UI Thread Wait and DeadLock

我希望这会有所帮助。

答案 2 :(得分:0)

我遇到了同样的问题,我发现问题是我调用的任务在单击“关闭”按钮后已经关闭了一秒钟,所以当调用函数需要更长时间时 - 它可能会崩溃。

如果您仍想执行此功能,我使用的是BeginInvoke而不是Invoke,而且效果正常。

这是我的代码:

if (app.Current.Dispatcher.CheckAccess()) //doesn't need to be invoked
    myFunction();
    else //coming from another thread need invoker
    {
        //at exiting program this task might already be canceled, so make sure it's not
        if (!app.Current.Dispatcher.HasShutdownFinished) 
            app.Current.Dispatcher.Invoke(myFunction());
        else   
            app.Current.Dispatcher.BeginInvoke(myFunction());