尽管使用BackgroundWorker,表单冻结,除非我们添加假睡眠

dis*_*kid 0 c# multithreading listbox backgroundworker winforms

我已经成功地完成了我BackgroundWorker的工作WinForm.它工作正常,但实际上它没有.从下面可以看出,我的形式有一个listbox以及一个Progress Bar.我正在使用它们来显示在一个文件中写一个收件人列表的进度for loop.我知道这个过程运行得太快了.每次写入一行时,都会listbox显示" 添加x个y收件人 "消息并删除其自身的最后一个条目,以便不会有太多文本.还有每个插入物,progress bar必须迈出一步.

在此输入图像描述

当我在每次写入中添加1ms延迟时,程序工作正常Thread.Sleep(1).我的表单仍然可以在桌面上移动,表单看起来很正常.但是当我删除这个睡眠时(这是真实场景),表单会冻结,就好像我从未使用过并行BackgroundWorker开始一样.我怎样才能克服这个问题?

以下是我的BackgroundWorker DoWork()ProgressChanged()事件:

做工作:

private void backgroundWorkerConvertDatatableToFile_DoWork(object sender, 
                                                           DoWorkEventArgs e)
{
    try
    {
        StringBuilder sb = new StringBuilder();
        IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>().
                                            Select(column => column.ColumnName);
        sb.AppendLine(string.Join(GetDelimiter(campaignOutputFormat), columnNames));
        backgroundWorkerConvertDatatableToFile.ReportProgress(-1, 
                                   dt.Rows.Count.ToString() + " recipients found.");
        for (int i = 0; i < dt.Rows.Count; i++)
        {
           IEnumerable<string> fields = dt.Rows[i].ItemArray.Select(
                                                    field => field.ToString());
           sb.AppendLine(string.Join(GetDelimiter(campaignOutputFormat), fields));
           backgroundWorkerConvertDatatableToFile.ReportProgress(i, 
            string.Format("Adding {0} of {1}...", (i + 1).ToString(), dt.Rows.Count));
           Thread.Sleep(1);
        }
        string outputFile = String.Format("{0}\\{1}.csv", 
                                            campaignOutputPath, campaignFileName);
        backgroundWorkerConvertDatatableToFile.ReportProgress(0, "Writing to file..");
        File.WriteAllText(outputFile, sb.ToString());
        convertSuccess = true;
    }
    catch (Exception ex)
    {
        logger.Log(LogLevel.Error, 
                   "FileCampaignRunner: ConvertDataTableToCSV", ex.Message);
        convertSuccess = false;
    }
    if (convertSuccess)
    {
        backgroundWorkerConvertDatatableToFile.ReportProgress(100, 
                                               "Write to file successful!");
    }
    else
    {
        backgroundWorkerConvertDatatableToFile.ReportProgress(100, 
                                               "Error writing to file.");
    }
}
Run Code Online (Sandbox Code Playgroud)

ProgressChanged:

private void backgroundWorkerConvertDatatableToFile_ProgressChanged(object sender,
                                                    ProgressChangedEventArgs e)
{
    switch (e.ProgressPercentage)
    {
        case -1:
            listBoxMessages.Items.Add(e.UserState.ToString());
            listBoxMessages.Items.Add("");
            break;
        case 100:
            listBoxMessages.Items.RemoveAt(listBoxMessages.Items.Count - 1);
            listBoxMessages.Items.Add(e.UserState.ToString());
            break;
        default:
            listBoxMessages.Items.RemoveAt(listBoxMessages.Items.Count - 1);
            listBoxMessages.Items.Add(string.Format(e.UserState.ToString()));
            progressBar.PerformStep();
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 5

当你经常调用ReportProgress()时,这是完全正常的.一个firehose问题,你要求UI线程做更多的工作然后它能够​​做.一旦它执行了一个委托目标,那么另一个目标可用,它永远无法赶上.它现在停止履行其他职责,响应输入和绘画窗口.它只是在派遣代表时燃烧100%的核心.调用队列在不受限制的情况下不断增长,但是在程序内存不足之前,用户会失去耐心,因此实际崩溃很少.

您需要通过不频繁地调用ReportProgress()来解决此问题.请记住,您只需要实现一个目标,保持用户的目光.这很容易,你的输出变成了一个难以理解的模糊,大约每秒20次更新.为您提供50倍的安全保证金.