簡體   English   中英

如何在執行異步操作期間控制進度條

[英]How to control progress bar during executing async operations

在為我的項目實施導出util的過程中,我在上傳文件時遇到阻止UI的問題。 基本上問題是在異步任務期間,我無法更新進度欄。

我已經嘗試了幾種解決方案。 通常,當我調用exportPopUp.ShowDialog()時,它會阻止copyAttachment()的執行,並且整個邏輯在關閉窗體后完成。 我決定使用Show(),但是當我這樣做時,表單還沒有保存(全灰色)

這是我的背景邏輯:

   private void exportButton_Click(object sender, EventArgs e)
    {
        // get files
        int row = reportsDataGrid.CurrentCell.RowIndex;
        if (row >= 0)
        {
            string problemId = reportsDataGrid.Rows[row].Cells[0].Value.ToString();
            AC.Trace.I("Problem Id", problemId);
            FolderBrowserDialog dlgFolderBrowser = new FolderBrowserDialog();
            dlgFolderBrowser.Description = "Select folder to save Report files!";
            DialogResult result = dlgFolderBrowser.ShowDialog();
            if (result == DialogResult.OK)
            {
                string folderName = dlgFolderBrowser.SelectedPath;
                AC.Trace.I("Destination folder name", folderName);
                CIS.PRS.Data.Attachments attachments = jampPrsService.ReportFiles(problemId);
                processAttachments(attachments, folderName, problemId);
            }
        }
    }

    private async void processAttachments(Attachments attachments, string folderName, string problemId)
    {
        this.exportPath = folderName + "\\" + problemId;
        cts = new CancellationTokenSource();
        this.exportPopUp = new exportPopUp(attachments.Size(), cts);
        this.exportPopUp.ExportFinished += ExportPopUp_ExportFinished;
        exportPopUp.setExportLabelText("Exporting problem report " + problemId);
        exportPopUp.ShowDialog();
        await copyAttachments(attachments, folderName, problemId);
    }

    private void ExportPopUp_ExportFinished()
    {
        this.finishExport();
    }

    private async Task copyAttachments(Attachments attachments, string folderName, string problemId)
    {
        //List<Task> tasks = new List<Task>();
        foreach (Attachment attachment in attachments.attachments)
        {
            //tasks.Add(Task.Factory.StartNew(() => copy(attachment, folderName, problemId)));
            await Task.Factory.StartNew(() => copy(attachment, folderName, problemId));
        }
        //await Task.WhenAll(tasks);
    }

    private void copy(Attachment attachment, string folderName, string problemId)
    {
        FileStream fs = null;
        if (!Directory.Exists(exportPath))
        {
            Directory.CreateDirectory(exportPath);
        }
        try
        {
            using (fs = new FileStream(Path.Combine(exportPath, attachment.Name), FileMode.Create))
            {
                fs.WriteAsync(attachment.Data, 0, attachment.Data.Length, this.cts.Token).Wait();
                fs.Flush();
                fs.Close();
                this.exportPopUp.performProgressBarStep();
            }
            AC.Trace.I("File has been saved: ", attachment.Name);
        }

        catch (Exception ex)
        {
            AC.Trace.E("Cannot write file " + attachment.Name, ex);
        }
    }
    private void finishExport()
    {
        this.exportPopUp.Close();
        this.exportPopUp.Dispose();
        MessageBoxCc.ShowInformation("Problem report exported succesfully. \n" +
                "Report exported to '"+ exportPath + "'", "Problem Request", "675");
    }
}

這是我的exportPopUp類:

public delegate void ExportFinishHandler();

    public partial class exportPopUp : Form
    {
        public event ExportFinishHandler ExportFinished;

        private CancellationTokenSource cancellationTokenSource;

        public exportPopUp(int progressBarSize, CancellationTokenSource cancellationTokenSource)
        {
            InitializeComponent();
            this.CenterToScreen();
            this.cancellationTokenSource = cancellationTokenSource;
            this.progressBar.Maximum = progressBarSize;
            this.progressBar.Step = 1;
            this.progressBar.Value = 0;        
        }

        public void setExportLabelText(string text)
        {
            exportLabel.Text = text;
        }

        public void performProgressBarStep()
        {
            this.progressBar.PerformStep();
            MessageBoxCc.ShowInformation("VALUE " + this.progressBar.Value + " MAX " + this.progressBar.Maximum, "KOZA", "123");
            if(this.progressBar.Value == this.progressBar.Maximum)
            {
                this.ExportFinished();
            }
        }

        private void cancelBtn_Click(object sender, EventArgs e)
        {
            cancellationTokenSource.Cancel();
        }
    }

通常,整個邏輯都能按我預期的那樣工作,但是我無法同時執行復制任務和更新進度欄。 提前致謝

更新

更改其預期的工作后,但是為了調用出口而不是從出口按鈕,其灰色和庫存再次出現。

我不是從導出按鈕附加此方法的執行

偵聽器類:

// Inner listener class 
public class ReportCreatedListener
{
    private frameProblemRequestReport frameProblemRequestReport;

    public ReportCreatedListener(frameProblemRequestReport frameProblemRequestReport)
    {
        this.frameProblemRequestReport = frameProblemRequestReport;
    }

    public async Task notifyRaportCreated(string problemId)
    {
        await this.frameProblemRequestReport.reportCreationFinished(problemId);
    }
}

電話:

    internal async Task reportCreationFinished(string lastProblemId)
    {
        if ((lastProblemId).Contains(report.ReportInfo.ProblemId))
        {
            string problemId = report.ReportInfo.ProblemId;
            string folderName = "C:\\Users\\Z006DQF6\\Desktop";
            AC.Trace.I("Exporting created raport to location: ", folderName);
            CIS.PRS.Data.Attachments attachments = jampPrsService.ReportFiles(lastProblemId);
            await processAttachments(attachments, folderName, problemId);
        }
    }

reportCreationFinished是從另一個偵聽器觸發的

    private class StateListener : CompoundStateListener
    {
        private JAMPPRSService service;
        public StateListener(JAMPPRSService service)
        {
            this.service = service;
        }
        public async void stateChanged(CompoundModel cm)
        {
            string lastSendReportId = cm.getMember("LastCreatedReportId").getValue().ToString();
            await service.reportCreatedListener.notifyRaportCreated(lastSendReportId);
        }
    }

我無法繼續前進,因為此事件來自用Java編寫的后端

這里的問題是從異步處理切換到同步。 您甚至在代碼中執行了兩次。

如果從async await開始,則需要在整個調用層次中進行繪制。

1)從點擊處理程序開始。 這應該是層次結構中唯一的async void方法。 在這里等待下一個

private async void exportButton_Click(object sender, EventArgs e)
{
    await processAttachments(attachments, folderName, problemId);
}

2)制作下一個調用方法以返回Task並使用Show這樣copyAttachments將在之后執行並可以等待

          return Task here
                |
                v
private async Task processAttachments(Attachments attachments, string folderName, string problemId)
{
    this.exportPath = folderName + "\\" + problemId;
    cts = new CancellationTokenSource();
    this.exportPopUp = new exportPopUp(attachments.Size(), cts);
    this.exportPopUp.ExportFinished += ExportPopUp_ExportFinished;
    exportPopUp.setExportLabelText("Exporting problem report " + problemId);
    exportPopUp.Show();  // <= !
    await copyAttachments(attachments, folderName, problemId);
}

3)使用從fs.WriteAsync返回的fs.WriteAsync並等待它。 再次使copy方法返回一個Task來向上傳播它:

private void copy(Attachment attachment, string folderName, string problemId)
{
    ...
    try
    {
        using (fs = new FileStream(Path.Combine(exportPath, attachment.Name), FileMode.Create))
        {
            awaitfs.WriteAsync(attachment.Data, 0, attachment.Data.Length, this.cts.Token);
            fs.Flush();
            fs.Close();
            this.exportPopUp.performProgressBarStep();
        }           
    }
    ...

4)等待復制方法(如果要一個接一個地復制附件):

private async Task copyAttachments(Attachments attachments, string folderName, string problemId)
{
    foreach (Attachment attachment in attachments.attachments)
    {            
        await copy(attachment, folderName, problemId));
    }
}

這應該會產生一個可行的解決方案,其中兩個表單都將保持響應狀態,並且您會看到進度條已滿。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM