如何从另一个线程同步UI和访问对象

本文关键字:UI 访问 对象 同步 线程 另一个 | 更新日期: 2023-09-27 18:14:53

我是并行编程和线程的新手。我想计算和添加级数到一个图表,不幸的是,这是一个相当耗时的任务。因此,我想在此期间展示一个加载屏幕:

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

当然这行不通。所以我想我需要在另一个线程中更新Chart控件。

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

然而,现在我得到不同的错误,大部分是我无法从另一个线程访问chartControl和设置。

我如何访问和改变UI从另一个线程和如何传递对象创建在一个线程到另一个?你能给我举个类似的例子吗?

如何从另一个线程同步UI和访问对象

从非UI线程更新UI线程上的控件,您必须这样做:

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

从这里开始:使用Dispatcher构建响应更快的应用程序
.NET线程初学者指南:第5部分
还有一个小例子:任务并行库:1 of n

你必须做这个

编辑/更新

这对我来说很好,但是de 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();
      }
    }
  }
}