开发者

UI Thread Block

开发者 https://www.devze.com 2023-04-06 18:45 出处:网络
I have created a simple WPF Application and added a button to the default window. When I click on the button, a simulated long working method(simulated using a Thread.Sleep(15000) is called. I am tryi

I have created a simple WPF Application and added a button to the default window. When I click on the button, a simulated long working method(simulated using a Thread.Sleep(15000) is called. I am trying to make the button execute asynchronously how开发者_如何学Goever despite following online examples, the button and entire window locks as soon as I click and remains so until the Thread.Sleep(...) finishes.

Any ideas why this is happening?

Here is the code:

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();
}


You are putting the long operation back into the UI thread. Let me comment your example:

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);
                })); 
      } 
    )); 

So, you should modify your example like this:

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
                })); 
      } 
    )); 

As others have mentioned, it's easier to use the BackgroundWorker class. Here's an example:

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
}


By using BeginInvoke you are actually executing the code on the UI thread.

You only need to use this when you are updating your UI from the background worker thread. If you simply have:

 Thread thread = new System.Threading.Thread(
     new System.Threading.ThreadStart(
      delegate()
      {
           Thread.Sleep(15000);
      }
    ));

I think it will work.

However, you aren't raising a "Work Completed" event so you have no way of knowing when (or indeed if) the thread has finished. Look into the BackgroundWorker class. This does a lot of the heavy lifting for you. You just need to plug in your code to the DoWork method.


You should use BackgroundWorker.

  • http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
  • http://www.tanguay.info/web/index.php?pg=codeExamples&id=232
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号