如何在长时间迭代期间使 GUI 响应

本文关键字:GUI 响应 迭代 长时间 | 更新日期: 2023-09-27 18:33:35

首先,我对编程比较陌生。我为我的新工作进行了一些 C# 入门培训,这是我使用过的第一门语言。

最近遇到了一个业务问题,我决定使用 C# 来解决,既可以节省时间(我希望如此(,也可以在此过程中学习更多的 C#。我提到的业务问题是:我需要审核 600+ Word 文件。对于每个文档,我必须确保...

  1. 文档中任何地方都没有带有删除线的文本。
  2. 修订已禁用。
  3. 没有挂起的更改(如在以下情况下所做的更改修订已启用,但尚未被接受或被拒绝(。
  4. 没有人发表评论。

让我的程序遍历所有文档,并在此过程中进行更改,这将是最快的。但是由于这个任务的性质,我想手动进行更改,将程序的使用限制为生成需要更改的文件列表(共 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 响应

我相信

你需要的东西可以在这里找到。简而言之,要使用在单独的线程上完成所有工作的后台工作线程,从而防止 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");