2011-11-17 106 views
0

我對並行編程和線程相當陌生。我想計算一系列圖表並將其添加到圖表中,這不幸是一項相當耗時的任務。所以我想在此期間展示一個加載屏幕:如何從另一個線程同步UI和訪問對象?

(.NET 4.0, WPF for UI) 

ShowLoadingScreen(true); 
CalculateAndUpdateChart(chartControl, settings); 
ShowLoadingScreen(false); 
... 
private void ShowLoadingScreen(bool show) { loadingScreen.IsBusy = show; } 
private void CalculateAndUpdateChart(ChartControl chart, ProductSettings settings) 
{ 
    chart.SomeSettings = ... 
    foreach(var item in settings.Items) 
    { 
     chart.Series.Points.Add(CalculateItem(item)); 
     ... 
    } 
} 

但是當然這是行不通的。所以我想我需要更新另一個線程中的圖表控件。

ShowLoadingScreen(true); 
Tash.Factory.StartNew(()=>{CalculateAndUpdateChart(chartControl, settings)}); 
ShowLoadingScreen(false); 

不過,現在我得到不同的錯誤,大多數的我怎麼不能從另一個線程訪問chartControl和設置。

如何訪問和更改另一個線程的UI形式以及如何將在一個線程中創建的對象傳遞給另一個線程?你能給我一個類似的例子,我想要做什麼?

+0

如果你想顯示在圖表上「建立」的時候,那麼內'CalculateAndUpdateChart調用(原樣);否則,如果你想全部一次,我建議運行一個任務到'CalculateItem'所有項目_then_一旦你有所有項目計算,調用更新圖表。 –

+0

你見過我的回答嗎? – punker76

回答

2

從非UI線程更新UI線程上的控件,你必須做到:

Dispatcher.Invoke(...); OR 
Dispatcher.BeginInvoke(...); 

從這裏開始: Build More Responsive Apps With The Dispatcher
和一點點的位置:Beginners Guide to Threading in .NET: Part 5 of n
和一個小例子: Task Parallel Library: 1 of n

+0

良好的聯繫。第一篇文章中的BackgroundWorker示例非常有用。當我知道我想將某些處理卸載到另一個線程時,我可能會使用這80%的時間,但我不在乎手動管理線程。我啓動一個「忙碌,請稍候」的屏幕,運行BackgroundWorker,當任務完成時,BackgroundWorker會在UI線程中引發一個事件,以便我可以更新控件並清除繁忙的屏幕。 – Kendrick

+0

@肯德里克:我通常也是這麼做的。雖然,當我有更多時間時,我真的很想深入TPL。 (BackgroundWorker仍然是如此可靠,它只是_works_。) –

0

你必須做,也許這一個

編輯/更新

這個工作對我很好,但德GUI線程仍然受阻是計算

using System.Threading; 
using System.Threading.Tasks; 
using System.Windows; 

namespace TPLSpielwiese 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
    public MainWindow() { 
     this.InitializeComponent(); 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) { 
     TaskScheduler taskUI = TaskScheduler.FromCurrentSynchronizationContext(); 
     Task.Factory 
     .StartNew(() => 
        { 
         this.ShowLoadingScreen(true); 
        }, CancellationToken.None, TaskCreationOptions.None, taskUI) 
     .ContinueWith((t) => 
         { 
          //CalculateAndUpdateChart(chartControl, settings); 
          Thread.Sleep(1000); 
         }, CancellationToken.None, TaskContinuationOptions.None, taskUI) 
     .ContinueWith((t) => 
         { 
          this.ShowLoadingScreen(false); 
         }, CancellationToken.None, TaskContinuationOptions.None, taskUI); 
    } 

    private Window loadScreen; 

    private void ShowLoadingScreen(bool showLoadingScreen) { 
     if (showLoadingScreen) { 
     this.loadScreen = new Window() {Owner = this, WindowStartupLocation = WindowStartupLocation.CenterOwner, Width = 100, Height = 100}; 
     this.loadScreen.Show(); 
     } else { 
     this.loadScreen.Close(); 
     } 
    } 
    } 
} 
+0

不,不起作用(你也有一些語法錯誤,但我修正了這些錯誤)。 – user315648

+0

好吧,我更新了我的答案 – punker76