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