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