Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何从另一个线程同步UI和访问对象?_C#_Wpf_Thread Safety - Fatal编程技术网

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

C# 如何从另一个线程同步UI和访问对象?,c#,wpf,thread-safety,C#,Wpf,Thread Safety,我对并行编程和线程相当陌生。我想计算并将序列添加到图表中,不幸的是,这是一项非常耗时的任务。所以我想同时显示一个加载屏幕: (.NET 4.0, WPF for UI) ShowLoadingScreen(true); CalculateAndUpdateChart(chartControl, settings); ShowLoadingScreen(false); ... private void ShowLoadingScreen(bool show) { loadingScreen.Is

我对并行编程和线程相当陌生。我想计算并将序列添加到图表中,不幸的是,这是一项非常耗时的任务。所以我想同时显示一个加载屏幕:

(.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,以及如何将在一个线程中创建的对象传递给另一个线程?请给出一个类似的例子,说明我正在尝试做什么?

从非UI线程要更新UI线程上的控件,必须执行以下操作:

Dispatcher.Invoke(...);  OR
Dispatcher.BeginInvoke(...);
从这里开始:
还有一点:

还有一个小例子:

你可能必须做这个

编辑/更新

这对我来说很好,但在计算时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();
      }
    }
  }
}
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows;
命名空间TPLSpielwiese
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口(){
this.InitializeComponent();
}
私有无效按钮\u单击(对象发送者,路由目标e){
TaskScheduler taskUI=TaskScheduler.FromCurrentSynchronizationContext();
任务,工厂
.StartNew(()=>
{
此。显示加载屏幕(true);
},CancellationToken.None,TaskCreationOptions.None,taskUI)
.ContinueWith((t)=>
{
//CalculateAndUpdateChart(图表控件、设置);
睡眠(1000);
},CancellationToken.None,TaskContinuationOptions.None,taskUI)
.ContinueWith((t)=>
{
此。显示加载屏幕(错误);
},CancellationToken.None,TaskContinuationOptions.None,taskUI);
}
私家窗口负荷屏幕;
专用void显示加载屏幕(bool显示加载屏幕){
如果(显示加载屏幕){
this.loadScreen=new Window(){Owner=this,WindowStartupLocation=WindowStartupLocation.CenterOwner,Width=100,Height=100};
this.loadScreen.Show();
}否则{
this.loadScreen.Close();
}
}
}
}

好的链接。第一篇文章中的BackgroundWorker示例非常有用。当我知道我想将一些处理转移到另一个线程,但我不想手动管理该线程时,我可能会有80%的时间使用这个线程。我启动一个“忙,请等待”屏幕,运行BackgroundWorker,当任务完成时,BackgroundWorker在UI线程中引发一个事件,我可以抓取该事件来更新控件并清除忙屏幕。@Kendrick:我通常也这样做。不过,当我有更多的时间时,我真的很想深入研究第三方物流。(BackgroundWorker仍然非常可靠。它可以正常工作。)如果您想显示图表“building up”,请在
CalculateAndUpdateChart
中调用(按原样);否则,如果您想要一次全部,我建议为所有项目运行一个任务以
CalculateItem
,然后在计算完所有项目后,调用以更新图表。您看到我的答案了吗?没有,不起作用(您也有一些语法错误,但我已修复这些错误)。