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
,然后在计算完所有项目后,调用以更新图表。您看到我的答案了吗?没有,不起作用(您也有一些语法错误,但我已修复这些错误)。