2016-02-03 77 views
0

我有一個很長的操作,在主UI上創建一些工具。在主線程中的長操作迫使UI掛起

當我運行此操作時UI掛起。 我想更新ProgressBar以指示操作狀態百分比,但不更新。

我的代碼如下所示:

Sub DoWork() 
    DoLongOperation() 
End sub 

sub DoLongOperation() 
For K as integer = 0 to 50 
    'Here I create tools and add them to a StackPanel in the window 
    'While doing this I update a progressBar value 
    ProgressBar1.value=Some value 
Next 
End sub 

我該怎麼辦呢? 我試着異步等待,但它無法處理創建工具到主UI的操作。

+0

你應該使用'IProgress'和'await'。有關詳細信息,請參見[此處](http://blog.stephencleary.com/2012/02/reporting-progress-from-async-tasks.html)。 –

+0

http://stackoverflow.com/a/18033198/2882256 –

+0

這很好,但不符合我想要做的。我的操作不能在單獨的線程中運行,因爲它會創建UI元素,而不僅僅是一個長操作。所以,我可以說。它不能有解決方案。 –

回答

0

我知道了。我把我的創作分成了50個部分。在創建一個工具的最後,我可以設置進度條。之後,我可以創建第二個。並繼續。

0

ProgressBar未更新的原因是您仍然阻塞主線程。您的長操作應該在一個額外的線程中調用。所以你可以使用例如Task.Run方法。 還有一件事要記住,在一個額外的線程中,你不能改變任何用戶界面,要做到這一點,你應該使用例如窗口的Dispatcher屬性。

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Task.Run(() => 
    { 
     for(int i = 0; i < 50; i++) 
     { 
      Thread.Sleep(1000); // some long operation 

      var progress = i*2; 

      Dispatcher.Invoke(() => 
      { 
       progressBar1.Value = progress; 
      }); 
     } 
    }); 
} 
+0

你能舉個例子嗎? –

+0

是的,但只在C#:) –

0

至於以更新UI,或者仍然使其暢通和可用的,而這樣做很長的操作,必須做其他線程操作之前說。您可以使用BackgroundWorker來做到這一點。如果你不想只爲新線程創建新的方法,你可以委託他們,你可以做這樣的事情:

Imports System.ComponentModel 
Sub DoLongOperation() 
    Dim bgWorker As New System.ComponentModel.BackgroundWorker() 
    bgWorker.WorkerReportsProgress = True 

    AddHandler bgWorker.DoWork, 
     Sub(sender, args) 
      For K as integer = 0 to 50 
       'Here I create tools and add them to a StackPanel in the window 
       'While doing this I update a progressBar value 

       bgWorker.ReportProgress(123) 
      Next 
     End Sub 

    AddHandler bgWorker.ProgressChanged, 
     Sub(sender, args) 
      ProgressBar.Value = args.ProgressPercentage 
     End Sub 

    AddHandler bgWorker.RunWorkerCompleted, 
     Sub(sender, args) 

     End Sub 

End sub 

既然你不能添加/刪除或做其他線程其他事情上StackPanel,你可以把你想要添加到bgWorker.ReportProgress()方法的項目,然後從.ProgressChanged事件更新它,所以它會是這樣的:

AddHandler bgWorker.DoWork, 
    Sub(sender, args) 
     For K as integer = 0 to 50 
      'Here I create tools and add them to a StackPanel in the window 
      'While doing this I update a progressBar value 

      Dim item As Object 'stackpanel's item that you want to add later on. Can be any type 

      bgWorker.ReportProgress(123, item) 
     Next 
    End Sub 

AddHandler bgWorker.ProgressChanged, 
    Sub(sender, args) 
     ProgressBar.Value = args.ProgressPercentage 
     StackPanel.Chlidren.Add(args.UserState) 
    End Sub 
+0

太棒了。我明白了。直到現在我還沒有測試它。但是,我會盡快。謝謝。 –

+0

我有這個錯誤「調用線程必須是STA,因爲許多UI組件都需要這個。」我在一個獨立的子文件中進行了創建操作,並使用 _對其進行了標記,但也無效。 –

+0

您可以嘗試調用Application.Current.Dispatcher.Invoke((Action)委託{}'方法或創建新的線程' –