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