繁体   English   中英

读取文件时冻结带有ProgressBar的窗体(C#WinForms)

[英]Form with ProgressBar is Frozen while reading file (C# WinForms)

在我的C# WinForms应用程序中,我具有MainForm,其中正在使用BackgroundWorker读取大型Text文件。

我还使用第二个窗体显示Marquee ProgressBar以通知用户他们必须等待文件被完全读取。

我遇到的问题是带有进度栏(SimpleProgressBar)的Form被冻结,直到读取文件为止。 BW应该位于单独的线程中,以免发生这种情况。

我留下了读取文件的代码,因为它可能与我的问题有关。 但是,所有代码实际上都可以正常工作,只是用于显示ProgressBar的Form已冻结。

SimpleProgressBar.cs(窗体)

//Simple Progress Bar set to Marquee
public partial class SimpleProgressBar : Form
{
    public SimpleProgressBar()
    {
        InitializeComponent();


        //ProgressBar is setup in the designer.
        /*
          System.Windows.Forms.ProgressBar progressBar1;
          this.progressBar1.Location = new System.Drawing.Point(16, 65);
          this.progressBar1.Name = "progressBar1";
          this.progressBar1.Size = new System.Drawing.Size(350, 23);
          this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
          this.progressBar1.TabIndex = 1;
        */

    }
}

MainForm.cs(窗体)

    //Class variable
    private SimpleProgressBar wait = new SimpleProgressBar();



    private void generatePreview()
    {
            //Setup BW Thread
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;
            worker.DoWork += worker_DoWork;
            worker.ProgressChanged += worker_ProgressChanged;
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;

            //Start procesing file
            worker.RunWorkerAsync();


            //Show the dialog
            wait.ShowDialog(); //perhaps .Show() would be better ?


    }

    //Once completed put the text into the textbox
    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        textBox1.Text  = ((StringBuilder)e.Result).ToString();

    }

    //Report progress here
    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {


    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bw = (BackgroundWorker)sender;

        int bufferSize = 1024;

        var sb = new StringBuilder();
        var buffer = new Char[bufferSize];
        var length = 0L;
        var totalRead = 0L;
        var count = bufferSize; 

        using (var sr = new StreamReader("c:\200mb_text_file.txt"))
        {
            if (bw.CancellationPending)
            {

            }
            else
            {
                length = sr.BaseStream.Length;
                while (count > 0)
                {
                    count = sr.Read(buffer, 0, bufferSize);
                    sb.Append(buffer, 0, count);

                    totalRead += count;
                }
            }
        }

        e.Result = sb;


    }

UPDATE

所以本质上,我想创建一个通用的第二表单来使用进度指示器,该指示器可以用于多种目的。

但是,BW看起来必须位于与需要更新的UI元素相同的线程上。

ShowDialog显示一个模式对话框,您必须显式关闭它。 当您调用ShowDialog ,该程序将无法继续执行。 您的后台工作者的完成事件必须关闭该对话框。

另外,您一次读取1,024个字节,然后调用progress事件。 每次对progress事件的调用都需要对UI线程进行封送处理。 读取1,024字节大约需要零时间,这意味着Progress事件将被连续调用,这又意味着UI线程将近100%占用您的进度更新。

如果确实需要在加载时报告进度,请使用更大的缓冲区。 无论如何,使用64 KB的缓冲区,您将获得更好的读取性能。 那是:

int bufferSize = 65536;

但是您的文件必须很大。 除非您的磁盘非常慢或者正在通过慢速网络进行读取,否则您应该至少每秒能够读取50兆字节。

进度条需要在另一个线程中进行更新,从UI线程更新进度条会导致冻结问题。 只需将代码更新到Backgroudnworker的DOWork方法中的进度栏​​即可,而不是报告它。

 void worker_DoWork(object sender, DoWorkEventArgs e)
    {
    stuffdone()
    progressBar1.PerformStep();

    }

在使用此功能之前,您需要设置Form.CheckForIllegalCrossThreadCalls = false; 这样BW可以访问UI

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM