UI线程块

fin*_*fin 9 wpf multithreading deadlock dispatcher

我创建了一个简单的WPF应用程序,并在默认窗口中添加了一个按钮.当我点击按钮时,会调用一个模拟的长工作方法(使用Thread.Sleep(15000)进行模拟).我试图使按钮异步执行,但是尽管有以下在线示例,按钮和整个窗口会立即锁定单击并保持不变,直到Thread.Sleep(...)结束.

任何想法为什么会这样?

这是代码:

private void button1_Click(object sender, RoutedEventArgs e)
{
   DoSomeAsyncWork();
}

private void DoSomeAsyncWork()
{
     System.Windows.Threading.Dispatcher.Run();
     Thread thread = new System.Threading.Thread(
         new System.Threading.ThreadStart(
          delegate()
          {
               Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => Thread.Sleep(15000)));
          }
        ));
     thread.Start();
}
Run Code Online (Sandbox Code Playgroud)

Hei*_*nzi 13

您将长操作放回UI线程.让我评论你的例子:

Thread thread = new System.Threading.Thread( 
    new System.Threading.ThreadStart( 
        delegate() { 
            // here we are in the background thread

            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
                new Action(() => {
                    // here we are back in the UI thread
                    Thread.Sleep(15000);
                })); 
      } 
    )); 
Run Code Online (Sandbox Code Playgroud)

所以,你应该像这样修改你的例子:

Thread thread = new System.Threading.Thread( 
    new System.Threading.ThreadStart( 
        delegate() { 
            // here we are in the background thread

            Thread.Sleep(15000);  // <-- do the long operation here

            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
                new Action(() => {
                    // here we are back in the UI thread

                    // do stuff here that needs to update the UI after the operation finished
                })); 
      } 
    )); 
Run Code Online (Sandbox Code Playgroud)

正如其他人所提到的,使用BackgroundWorker类更容易.这是一个例子:

private void DoSomeAsyncWork()   
{   
    BackgroundWorker bw = new BackgroundWorker();

    bw.DoWork += (sender, args) => {
        // do your lengthy stuff here -- this will happen in a separate thread
        Thread.Sleep(15000);
    }

    bw.RunWorkerCompleted += (sender, args) => {
        if (args.Error != null)  // if an exception occurred during DoWork,
            MessageBox.Show(args.Error.ToString());  // do your error handling here

        // do any UI stuff after the long operation here
        ...
    }

    bw.RunWorkerAsync(); // start the background worker
}
Run Code Online (Sandbox Code Playgroud)