我有一个背景工作者,它会进行一些计算并将进度结果报告为字符串。需要将此字符串插入dataGridView。但是在插入值时,GUI会冻结。
private void bckgrSorter_DoWork(object sender, DoWorkEventArgs e)
{
for (int i=0; i<1000; i++)
{
// doing some calculations
bckgrSorter.ReportProgress(i, someString);
}
}
private void bckgrSorter_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string results = (string)e.UserState;
dataGridView1.Rows.Add(results);
}
因此即使我在后台线程上进行了所有繁重的计算,由于DataGridView,GUI仍然会冻结。
编辑代码:
private void bckgrSorter_DoWork(object sender, DoWorkEventArgs e)
{
string[] folders = // some folders to get File List from
bckgrFileScanner.RunWorkerAsync(folders);
}
private void bckgrFileScanner_DoWork(object sender, DoWorkEventArgs e)
{
string[] folders = (string[])e.Argument;
foreach (string f in folders)
{
GetFileList(ref scannedFiles, f, bckgrFileScanner);
bckgrFileScanner.ReportProgress(1);
}
}
public void GetFileList(ref List<FileInfo> fList, string fPath, BackgroundWorker scanner)
{
DirectoryInfo di = new DirectoryInfo(fPath);
FileInfo[] fi = di.GetFiles();
foreach (FileInfo fiTemp in fi)
{
//ar ~$ saakas nevajadzīgie temp faili, tos izlaižam
if (fiTemp.Name.StartsWith("~$") == false)
{
fList.Add(fiTemp);
scanner.ReportProgress(0, fiTemp.Name);
}
}
DirectoryInfo[] dFolders = di.GetDirectories();
//katrai apakšmapei rekursīvi izsaucam šo funkciju
foreach (DirectoryInfo d in dFolders)
{
GetFileList(ref fList, d.FullName, scanner);
}
}
private void bckgrFileScanner_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 0)
{
filesDataGrid.Rows.Add(e.UserState);
}
else progressBar1.PerformStep();
}
答案 0 :(得分:1)
在我看来,您需要批处理工作线程的结果。也许你可以让ProgressChanged事件返回一系列进度结果或什么?或者只使用最新数据每半秒发生一次事件。我怀疑问题是你只是试图过快地添加数据。您需要在每个单元中完成更少的工作单元(一次添加大量行)。
巴巴尔是对的。像这样的东西可能会做你想要的(我还没有尝试编译它):
public void GetFileList(ref List<FileInfo> fList, string fPath, BackgroundWorker scanner)
{
DirectoryInfo di = new DirectoryInfo(fPath);
FileInfo[] fi = di.GetFiles();
List<string> progressData = new List<string>();
foreach (FileInfo fiTemp in fi)
{
//ar ~$ saakas nevajadzigie temp faili, tos izlaižam
if (fiTemp.Name.StartsWith("~$") == false)
{
fList.Add(fiTemp);
progressData.Add(fiTemp.Name);
if (progressData.Count > 50){
scanner.ReportProgress(0, progressData.ToArray());
progressData.Clear();//You've just copied the data to an array and sent it to the GUI, clear the list and start counting up again
}
}
}
if (progressData.Count > 0){
scanner.ReportProgress(0, progressData.ToArray());
}
DirectoryInfo[] dFolders = di.GetDirectories();
//katrai apakšmapei rekursivi izsaucam šo funkciju
foreach (DirectoryInfo d in dFolders)
{
GetFileList(ref fList, d.FullName, scanner);
}
}
这不是一个非常好的解决方案,但它是一个开始......
您还需要将e.UserState强制转换为回调中的字符串数组......
答案 1 :(得分:1)
一旦发现文件名,就会将文件名添加到网格中。在一个合理大小的目录上,这将很容易地重载UI线程与在网格中添加行的请求。结果你的用户界面冻结了。
以下是更新代码的方法。代码应该维护到目前为止发现的文件列表,而不是为单个文件调用ReportProgress()。一旦列表达到阈值大小100,那么你应该调用ReportProgress()并将该列表作为UserState传递。
这将显着减少对UI线程的调用次数,使您的应用程序响应。
答案 2 :(得分:0)
是否存在暂时停止控件更新的控件属性?可悲的是,我不记得这个名字。
您还可以尝试在后台创建控件,并在完成后将其添加到表单中。但要小心避免线程问题。
另一个想法是在更新期间隐藏它。
一个绝对“有效”的丑陋解决方案是让你的后台线程一次添加一个项目,等待几毫秒(在此期间GUI线程可以实际执行更改),并添加下一个项目。这将花费很长时间,但GUI在更新期间不会冻结。