Winforms背景工作者被困住

时间:2015-03-01 19:57:01

标签: c# winforms backgroundworker

我正在尝试构建一个将csv文件连接到一个不同文件的简单代码,但我的后台工作者似乎有自己的想法,我的代码每次都被卡住了。 这是我使用后台工作者加入文件的代码:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            if (string.IsNullOrEmpty(saveFilePath))
            {
                this.Invoke(new MethodInvoker(delegate
                {
                    btnBrowseSave.PerformClick();
                }));
            }
            if (!string.IsNullOrEmpty(saveFilePath))
            {
                if (dragEventArgs != null)
                    files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);

                int filesCount = 0, rowsCount = 0;
                foreach (string file in files)
                {
                    filesCount++;
                    int fileTotalLines = File.ReadAllLines(file).Length;

                    this.Invoke(new MethodInvoker(delegate
                    {
                        lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
                        lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
                    }));

                    using (StreamReader reader = new StreamReader(file))
                    {
                        using (StreamWriter writer = new StreamWriter(saveFilePath))
                        {
                            while (!reader.EndOfStream)
                            {
                                try
                                {
                                    while (stopPosition > rowsCount)
                                    {
                                        reader.ReadLine();
                                        rowsCount++;
                                    }
                                    string email = reader.ReadLine().Trim();
                                    if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
                                    {
                                        dicEmails.Add(email, null);
                                        writer.WriteLine(email);
                                    }
                                    rowsCount++;
                                    stopPosition++;

                                    backgroundWorker.ReportProgress((rowsCount * 100 / fileTotalLines), (int)ProgressType.Row);
                                    if (backgroundWorker.CancellationPending)
                                        return;
                                }
                                catch (Exception ex)
                                {
                                    hadReadErrors = true;
                                }
                            }
                        }
                    }
                    backgroundWorker.ReportProgress(0, (int)ProgressType.Row);
                    backgroundWorker.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
                }
            }
        }
        catch (Exception ex)
        {
            hadReadErrors = true;
            MessageBox.Show(ex.Message);
        }
        finally
        {
            backgroundWorker.Dispose();
        }
    }

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        try
        {
            switch ((int)e.UserState)
            {
                case (int)ProgressType.Row:
                    lblFileProgress.Text = e.ProgressPercentage + "%";
                    fileProgressBar.Value = e.ProgressPercentage;
                    break;
                case (int)ProgressType.File:
                    lblTotalProgress.Text = e.ProgressPercentage + "%";
                    totalProgressBar.Value = e.ProgressPercentage;
                    break;
            }
        }
        catch (Exception ex) { }
    }

当我在调试模式下运行并使用调试器时,我没有看到任何问题,但当我让代码自行运行时,它会卡住并崩溃。 有人可以帮助我,告诉我在这里错过了什么?

以下是例外:

Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a problem in    
'C:\Users\Develop\Desktop\ExcelBuilder\ExcelBuilder\bin\Debug\ExcelBuilder.vshost.exe'.

Additional information: The CLR has been unable to transition from COM context 0x90fb78 
to COM context 0x90fc30 for 60 seconds. The thread that owns the destination
context/apartment is most likely either doing a non pumping wait or processing a very 
long running operation without pumping Windows messages. This situation generally has 
a negative performance impact and may even lead to the application becoming non 
responsive or memory usage accumulating continually over time. To avoid this problem, 
all single threaded apartment (STA) threads should use pumping wait primitives 
(such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

1 个答案:

答案 0 :(得分:2)

我做了一个关于你的程序的小例子,试图猜测它必须做什么(https://github.com/anderson-rancan/stackoverflow_28798348,将4个文件拖放到groupbox,lorem?.csv),还有一些你应该做的事情考虑:

所以,只需修复它就可以运行它,就像这样:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker bckw = (BackgroundWorker)sender; // Recommended way, thread safe

    try
    {
        if (string.IsNullOrEmpty(saveFilePath))
        {
            this.Invoke(new MethodInvoker(delegate
            {
                btnBrowseSave.PerformClick();
            }));
        }
        if (!string.IsNullOrEmpty(saveFilePath))
        {
            if (dragEventArgs != null)
                files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);

            int filesCount = 0, rowsCount = 0;
            foreach (string file in files)
            {
                filesCount++;
                double fileTotalLines = File.ReadAllLines(file).Length;

                this.BeginInvoke(new MethodInvoker(delegate
                {
                    lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
                    lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
                })); // Invoke async, way too fast this...

                using (StreamReader reader = new StreamReader(file))
                {
                    using (StreamWriter writer = new StreamWriter(saveFilePath))
                    {
                        while (!reader.EndOfStream)
                        {
                            try
                            {
                                while (stopPosition > rowsCount)
                                {
                                    reader.ReadLine();
                                    rowsCount++;
                                } // why are you using that? it won't get TRUE

                                string email = reader.ReadLine().Trim();
                                if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
                                {
                                    dicEmails.Add(email, null);
                                    writer.WriteLine(email);
                                }
                                rowsCount++;
                                stopPosition++;

                                bckw.ReportProgress((int)Math.Round(rowsCount * 100 / fileTotalLines, 0), (int)ProgressType.Row);
                                if (bckw.CancellationPending)
                                    return;
                            }
                            catch (Exception ex)
                            {
                                hadReadErrors = true;
                                throw; // Throw it again, or you won't know the Exception
                            }
                        }
                    }
                }
                bckw.ReportProgress(0, (int)ProgressType.Row);
                bckw.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
            }
        }
    }
    catch (Exception ex)
    {
        hadReadErrors = true;
        MessageBox.Show(ex.Message);
    }
    finally
    {
        bckw.Dispose();
    }
}

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //try
    //{
    switch ((int)e.UserState)
    {
        case (int)ProgressType.Row:
            lblFileProgress.Text = e.ProgressPercentage + "%";
            if (e.ProgressPercentage <= fileProgressBar.Maximum)
                fileProgressBar.Value = e.ProgressPercentage;
            break;
        case (int)ProgressType.File:
            lblTotalProgress.Text = e.ProgressPercentage + "%";
            totalProgressBar.Value = e.ProgressPercentage;
            break;
    }
    //}
    //catch (Exception ex) { } // Don't catch everything
}

最后,我可以建议另一种方法吗? 您正在读取文件两次:一个用于获取行数,另一个用于读取每一行。尝试只做一次,你会得到更好的结果。