如何从另一个线程同步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线程上的控件,您必须这样做:
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();
}
}
}
}