簡體   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