繁体   English   中英

Parallel.ForEach 未更新 Windows 表单 UI

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM