2011-09-23 74 views
7

我創建了一個簡單的WPF應用程序,並添加一個按鈕,默認的窗口。當我按一下按鈕,模擬較長的工作方法(使用Thread.sleep代碼(15000),模擬被調用。我試圖使按鈕異步然而,儘管下面網上的例子執行,一旦按鈕,整個窗鎖,我單擊並一直持續到下了Thread.Sleep(...)結束UI線程塊

任何想法,爲什麼發生這種情況

這裏是代碼:?

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

回答

12

你把長運回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); 
       })); 
     } 
    )); 

所以,你應該修改你這樣的例子:

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

正如其他人所說,它更容易使用的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 
} 
3

使用BeginInvoke你實際上是在執行UI線程上的代碼。

你只需要當你從後臺輔助線程更新UI使用此。如果你只是有:

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

我認爲它會工作。

但是,你是不是養了「完成工作」事件,這樣你沒有的時候(或者實際上如果)線程完成得知。看看BackgroundWorker class。這爲你做了很多繁重的工作。您只需將代碼插入DoWork方法即可。

+0

我實際上是試圖執行需要它自己的線程一些代碼,當我把這一行代碼,直接在第一代表(即,你必須Thread.sleep代碼(15000))我得到一條消息說線程不能訪問對象。這是消息:「調用線程不能訪問此對象,因爲不同的線程擁有它。」顯然,這是一個常見問題,但我如何努力解決這個問題,而不需要使用後臺工作人員。因此,當我添加第二個嵌套的BeginInvoke調用時,找到該對象但UI被阻止。 – fin

+0

所以我想,我正在尋找的是一種方法,把我的邏輯看起來需要訪問新的後臺線程上的UI線程。總結一下,授予對UI對象的訪問權限,但在後臺的單獨線程中運行? – fin

+0

@Finbar:你不能「授予訪問權限」。 UI操作*必須*在UI線程中完成。然而,你可以做的是將UI操作分成小塊,將大循環放在後臺線程中,並在循環內部調用'Dispatcher.BeginInvoke(... short UI operation ...)'。這會導致用戶界面很快被阻止很多次,而不是很長時間。 – Heinzi