如何在长时间迭代期间使 GUI 响应
本文关键字:GUI 响应 迭代 长时间 | 更新日期: 2023-09-27 18:33:35
首先,我对编程比较陌生。我为我的新工作进行了一些 C# 入门培训,这是我使用过的第一门语言。
我最近遇到了一个业务问题,我决定使用 C# 来解决,既可以节省时间(我希望如此(,也可以在此过程中学习更多的 C#。我提到的业务问题是:我需要审核 600+ Word 文件。对于每个文档,我必须确保...
- 文档中任何地方都没有带有删除线的文本。
- 修订已禁用。
- 没有挂起的更改(如在以下情况下所做的更改修订已启用,但尚未被接受或被拒绝(。
- 没有人发表评论。
让我的程序遍历所有文档,并在此过程中进行更改,这将是最快的。但是由于这个任务的性质,我想手动进行更改,将程序的使用限制为生成需要更改的文件列表(共 600 个(,并详细说明需要对每个文件进行哪些更改。
所以,我有一个按钮可以调用文件夹浏览器对话框。
private void AddFolderButtonClick(object sender, EventArgs e)
{
var folderBrowser = new FolderBrowserDialog();
if (folderBrowser.ShowDialog() != DialogResult.OK)
{
return;
}
this.progressBar1.Visible = true;
this.progressBar1.Style = ProgressBarStyle.Marquee;
this.Cursor = Cursors.WaitCursor;
var args = new List<string>(Directory.EnumerateDirectories(folderBrowser.SelectedPath));
// Get list of files in selected directory, adding to list of directories
args.AddRange(Directory.EnumerateFiles(folderBrowser.SelectedPath));
this.displayListBox.BeginUpdate();
foreach (string path in args)
{
if (File.Exists(path))
{
// This path is a file
this.ProcessFile(Path.GetFullPath(path));
}
else if (Directory.Exists(path))
{
// This path is a directory
this.ProcessDirectory((Path.GetFullPath(path)));
}
else
{
Console.WriteLine(Resources.Finder_Invalid_File_Or_Directory, path);
}
}
this.displayListBox.EndUpdate();
this.progressBar1.Visible = false;
this.progressBar1.Style = ProgressBarStyle.Continuous;
this.Cursor = Cursors.Default;
}
以下两种方法一起循环访问所有子目录和文件,以创建通过 FolderBrowserDialog 选择的顶级目录下所有文件的完整列表:
private void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the directory.
string[] fileEntries = Directory.GetFiles(targetDirectory);
foreach (string fileName in fileEntries)
{
this.ProcessFile(fileName);
}
// Recurse into subdirectories of this directory.
string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string subdirectory in subdirectoryEntries)
{
this.ProcessDirectory(subdirectory);
}
}
private void ProcessFile(string path)
{
Console.WriteLine(Resources.Finder_File_Processed, path);
string fileName = Path.GetFileName(path);
if (fileName == null || fileName.StartsWith(@"~$") || this.selectedFilesList.Contains(path))
{
return;
}
this.selectedFilesList.Add(path);
this.filePathsCountLabel.Text = (@"Count: " + this.selectedFilesList.Count);
this.displayListBox.Items.Add(path);
}
一旦所有这些代码都运行了,我就会得到一个完整的文档列表。我单击一个按钮,程序从这里开始执行它应该做的事情。好吧,很酷。我之前提到过,我选择使用 C# 来解决这个问题的一半原因是为了学习。在这一点上,我已经拥有了我需要的一切,但我真正想知道的是,在生成文件列表时,如何实现线程以使 GUI 响应?我看了几个例子。他们是有道理的。出于某种原因,我只是无法理解此应用程序。如何在不锁定 GUI 的情况下完成处理子目录和文件的整个过程?
你需要的东西可以在这里找到。简而言之,要使用在单独的线程上完成所有工作的后台工作线程,从而防止 GUI 冻结,首先实例化 BackgroundWorker 并处理 DoWork 事件。然后调用 RunWorkerAsync,可以选择使用对象参数。
作为骨架代码:
class myClass
{
static BackgroundWorker myBw = new BackgroundWorker();
static void Main()
{
myBw .DoWork += myBw_DoWork;
myBw .RunWorkerAsync ("an argument here");
Console.ReadLine();
}
static void myBw_DoWork (object sender, DoWorkEventArgs e)
{
// This is called on the separate thread, argument is called as e.Argument
// Perform heavy task...
}
}
您必须创建一个单独的线程来处理您的工作。如果您使用的是 .NET 4.0+ 或旧版本,请查看此内容。
使用任务,您可以编写
Task.Factory.StartNew(() => DoAction()
其中 DoAction 是开始处理数据的函数。
但是不要忘记使用调用,如果你想从单独的线程使用 GUI。例如,如果要从单独的线程更新某些标签文本,则必须执行此操作
label1.Invoke(() => label1.Text = "Some Text");