在为我的项目实施导出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编写的后端
答案 0 :(得分:1)
这里的问题是从异步处理切换到同步。您甚至可以在代码中执行两次。
如果从异步等待开始,则需要在整个调用层次中进行绘制。
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
返回的任务并等待它。再次使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));
}
}
这应该产生一个可行的解决方案,其中两个表单都将保持响应状态,并且您会看到进度条充满了。