[英]Parallel.ForEach is not updating the Windows form UI
我有一个 windows 表格,我可以在其中输入一次要创建的记录数。 如果我提到创建 100 万条记录,则使用 for 循环使用单个线程需要更多时间。 所以我正在尝试使用Parallel.ForEach
在一批 100/10(可配置)中创建这 100 万条记录。 在操作进行时,我正在尝试更新 UI 文本框中的进度(例如显示已完成的许多记录)。 但问题是,直到调用Parallel.ForEach
进度状态文本框正在更新但在Parallel.ForEach
操作中,UI 元素没有更新。 完成Parallel.ForEach
后只有一次更新。
public partial class CreateRecordsForm : Form
{
private void CreateRecordsBtn_Click(object sender, EventArgs e)
{
this.progressStatusTxt.Text = "Started Creating Records"; //Updating in UI
int count = 0;
await Task.Run(() => Parallel.ForEach(bulkCreateRequests, new ParallelOptions { MaxDegreeOfParallelism = parallelThreadsSizeInt }, request =>
{
dataservice.CreateRecords(request);
Interlocked.Increment(ref count);
string progressStatus = count + " of " + bulkCreateRequests.Count + " Requests Completed";
this.progressStatusTxt.Text = progressStatus; //NOT updating in UI
}));
await Task.WhenAll();
this.progressStatusTxt.Text = "Finished Creating Records"; //Updating in UI
}
}
我尝试通过创建一个委托来更新 UI,但仍然无法正常工作。
public delegate void BulkOrderCreateFormDelegate(string status);
//...
public BulkOrderCreateFormDelegate BulkOrderCreateFormCallback;
//...
BulkOrderCreate()
{
this.BulkOrderCreateFormCallback += new BulkOrderCreateFormDelegate(this.SetProgressStatusValueFn);
}
private void SetProgressStatusValueFn(string progressStatusValue)
{
if(!string.IsNullOrWhiteSpace(progressStatusValue))
this.progressStatusTxt.Text = progressStatusValue;
}
private void CreateRecordsBtn_Click(object sender, EventArgs e)
{
this.progressStatusTxt.Text = "Started Creating Records"; //Updating in UI
int count = 0;
await Task.Run(() => Parallel.ForEach(bulkCreateRequests, new ParallelOptions { MaxDegreeOfParallelism = parallelThreadsSizeInt }, request =>
{
dataservice.CreateRecords(request);
Interlocked.Increment(ref count);
string progressStatus = count + " of " + bulkCreateRequests.Count + " Requests Completed";
BulkOrderCreateFormCallback(progressStatus); //Getting error : Cross thread operation
}));
await Task.WhenAll();
this.progressStatusTxt.Text = "Finished Creating Records"; //Updating in UI
}
有人知道该怎么做吗? 你能给我参考一个示例工作代码吗?
要报告进度,您可以使用Progress<T>
class 和IProgress<T>
接口。 在 UI 线程上实例化Progress<T>
class 很重要,因为它在实例化期间捕获当前SynchronizationContext
,并使用捕获的上下文传播进度消息。
public partial class CreateRecordsForm : Form
{
private async void CreateRecordsBtn_Click(object sender, EventArgs e)
{
IProgress<string> progress = new Progress<string>(
message => this.progressStatusTxt.Text = message);
progress.Report("Started Creating Records");
int count = 0;
ParallelOptions options = new() { MaxDegreeOfParallelism = parallelThreadsSizeInt };
await Task.Run(() => Parallel.ForEach(bulkCreateRequests, options, request =>
{
dataservice.CreateRecords(request);
int localCount = Interlocked.Increment(ref count);
string progressStatus = localCount + " of " +
bulkCreateRequests.Count + " Requests Completed";
progress.Report(progressStatus);
}));
progress.Report("Finished Creating Records");
}
}
UI 控件类似于 UI 线程。 它们应该仅在此线程上进行操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.