这是我的情景: 在表单上,我有一个目录列表,按钮和控件,以显示多行文字。 在循环中,我尝试查找每个目录中的所有文件并删除它们。 删除文件时,我想将文本添加到多行控件。 我的问题是,当添加文本时,我无法做任何其他事情。表单被阻止,如果我尝试做任何操作它只是停止响应。 使用BackgroundWorker
删除文件private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//this is datatable with directories and other info
MainDataset.CZYSZCZENIEDataTable CZYSZCZENIE = e.Argument as MainDataset.CZYSZCZENIEDataTable;
CzyscPliki(CZYSZCZENIE, ReportProgress);
}
private void CzyscPliki(MainDataset.CZYSZCZENIEDataTable CZYSZCZENIE, ReportProgressDel del)
{
DirectoryInfo dir = null;
FileInfo[] files = null;
bool subfolder = false;
string katalog = "";
string maska = "";
string[] maski = null;
long total=0;
string dirS;
string fileS;
long fileLen;
//foreach directory to delete
foreach (DataRow r in CZYSZCZENIE.Rows)
{
//CanRead - check if row is not deleted or detached
//r["CZYSC"].AsBool() - check if directory should be cleared
if (r.CanRead() && r["CZYSC"].AsBool())
{
subfolder = r["PODKATALOGI"].AsBool();
katalog = r["KATALOG"].AsString().TrimEnd('\\');
maska = r["MASKA"].AsString();
if (maska.IsEmpty())
maska = "*";
maski = maska.Split(';');
dir = new DirectoryInfo(katalog);
if (dir.Exists)
{
foreach (string s in maski)
{
files = dir.GetFiles(s, (subfolder ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly));
dir.GetFiles();
foreach (FileInfo f in files)
{
dirS = f.Directory.FullName;
fileS = f.Name;
fileLen = f.Length;
try
{
f.Delete();
total += fileLen;
if (del != null)
//here is problem: del - delegate to report state
//when it is called it blocks form
del(dirS, fileS, fileLen, total);
}
catch (Exception ex)
{ }
}
}
}
}
}
}
//this is the delegate that appends text in multiline control
//memoEdit1 is the control
//ceReportProgress.Checked - check if report should be added
private void ReportProgress(string directory, string file, long size, long totalSize)
{
if (memoEdit1.InvokeRequired)
{
memoEdit1.BeginInvoke(new Action<string, string, long, long>(ReportProgress), directory, file, size, totalSize);
}
else
{
if (ceReportProgress.Checked)
{
if (file.IsEmpty())
memoEdit1.AppendText("\r\nCzyszczenie katalogu " + directory);
else
{
memoEdit1.AppendText(file);
if (size > 0)
{
if (size > 1048576)
{
decimal d = size / 1048576;
d = decimal.Round(d, 2);
memoEdit1.AppendText("\tWielkość : " + d.AsString() + " megabajtów", false);
}
else if (size > 1024)
{
decimal d = (decimal)size / (decimal)1024;
d = decimal.Round(d, 2);
memoEdit1.AppendText("\tWielkość : " + d.AsString() + " kilobajtów", false);
}
else
memoEdit1.AppendText("\tWielkość : " + size.AsString() + " bajtów", false);
}
if (totalSize > 0)
{
if (totalSize > 1073741824)
{
decimal d = (decimal)totalSize / (decimal)1073741824;
d = decimal.Round(d, 2);
memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " gigabajtów");
}
else if (totalSize > 1048576)
{
decimal d = (decimal)totalSize / (decimal)1048576;
d = decimal.Round(d, 2);
memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " megabajtów");
}
else if (totalSize > 1024)
{
decimal d = (decimal)totalSize / (decimal)1024;
d = decimal.Round(d, 2);
memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " kilobajtów");
}
else
memoEdit1.AppendText("Zwolniono dotychczas : " + totalSize.AsString() + " bajtów");
}
}
//scroll to the end of control
memoEdit1.ScrollToEnd();
}
}
}
如何改进此功能,使其不会阻止表单?
答案 0 :(得分:2)
您经常调用ReportProgress。每秒执行超过1000次,并且UI线程充斥着它无法跟上的请求。它无法完成正常工作,包括绘制控件和响应鼠标和键盘。它看起来很冷冻。当UI更新代码变得更加昂贵时,这会变得更糟,当TextBox中已有大量文本变得非常慢时,更新TextBox中的文本。
在BGW停止运行后诊断仍然看到UI冻结一段时间,在清空调用请求队列中的积压工作时,然后在队列最终清空时突然恢复活跃。
您需要限制调用BeginInvoke()的速率。更频繁地称呼它比每50毫秒更频繁一次,人类无法察觉超出这一点的差异。收集列表中的信息&lt;&gt;所以你可以减少BeginInvoke()的频率。如果你的工作人员能够比UI线程能够跟上的速度更快地产生结果,那仍然不能完全保证。在这种情况下,减慢工人的速度将是一个解决方案。使用Invoke而不是BeginInvoke很容易。
答案 1 :(得分:0)
如果此工作程序异步运行,那么您可以拥有一个响应您的表单。
此外,问题:
您正在另一个函数中运行循环 - 它使操作非反复。
您甚至没有检查用户是否要取消(只是我想要的一个点) - 在DoWorkEventArgs
循环内处理Cancel
的{{1}}属性。< / p>
将函数foreach
的代码移到CzyscPliki
中(无论如何太小)。
编辑:
如果您不想将代码移动到backgroundWorker1_DoWork
事件处理程序中,那么最好使用DoWork
进行更多控制。我不是它的专家,但你会发现很多关于如何实现的代码。