Winforms递归文件扫描块UI

时间:2015-12-14 15:37:24

标签: winforms search asynchronous recursion task

我有一个程序搜索给定目录并将所有文件添加到列表视图中。我的问题是在搜索繁忙时ui线程卡住了。我尝试过使用任务但无法让它在异步中工作。找到每个文件后,必须更新列表视图。

我已经做了很多关于TPL的阅读以及如何使用它但在这种情况下无法使它工作。我得到了它的工作,其中数据处理在一个方法中创建一个任务来处理它。任何人都可以告诉我下面的代码有什么问题以及如何解决它?

这是我的代码:

private void button1_Click(object sender, EventArgs e)
{
    Task.Run(() =>
    {
        WalkDirectory(new DirectoryInfo(drive));
    });
}

public void testTaskUpdateLabel(string labelTeks)
{
    Task taskUpdateLabel = new Task(() =>
    {
        label4.Text = labelTeks;
    });
    taskUpdateLabel.Start(uiScheduler);
}

public void testTaskUpdateLabel(string labelTeks)
{
    Task taskUpdateLabel = new Task(() =>
    {
        label4.Text = labelTeks;
    });
    taskUpdateLabel.Start(uiScheduler);
}

public bool WalkDirectory(DirectoryInfo directory)
{
    if (directory == null)
    {
        throw new ArgumentNullException("directory");
    }
    return this.WalkDirectories(directory);
}

private bool WalkDirectories(DirectoryInfo directory)
{
    bool continueScan = true;
    continueScan = WalkFilesInDirectory(directory);

    if (continueScan)
    {
            DirectoryInfo[] subDirectories = directory.GetDirectories();

            foreach (DirectoryInfo subDirectory in subDirectories)
            {
                try
                {
                    if ((subDirectory.Attributes & FileAttributes.ReparsePoint) != 0)
                    {
                        continue;
                    }
                    if (!(continueScan = WalkDirectory(subDirectory)))
                    {
                        break;
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    continue;
                }
            }
    }
    if (continueScan)
    {
        testTaskUpdateLabel(directory.FullName);
    }
    return continueScan;
}

private bool WalkFilesInDirectory(DirectoryInfo directory)
{
    bool continueScan = true;
    // Break up the search pattern in separate patterns
    string[] searchPatterns = _searchPattern.Split(';');

    // Try to find files for each search pattern
    foreach (string searchPattern in searchPatterns)
    {
        if (!continueScan)
        {
            break;
        }
        // Scan all files in the current path
        foreach (FileInfo file in directory.GetFiles(searchPattern))
        {
            try
            {
                testTaskUpdate(file.FullName);
            }
            catch (UnauthorizedAccessException)
            {
                continue;
            }
        }
    }
    return continueScan;           

}

3 个答案:

答案 0 :(得分:3)

如果您使用BackgroundWorker类,则UI将起作用,并且可以在ProgressChanged事件处理程序中更新进度。

MSDN Reference

答案 1 :(得分:0)

  

任何人都可以告诉我下面的代码中有什么问题以及如何修复它?

问题出在这里

public void testTaskUpdateLabel(string labelTeks)
{
    Task taskUpdateLabel = new Task(() =>
    {
        label4.Text = labelTeks;
    });
    taskUpdateLabel.Start(uiScheduler);
}

您不应使用TPL更新UI。 TPL任务用于执行非UI工作,UI应仅在UI线程上更新。您已经在线程池线程上移动了工作(通过Task.Run),因此您需要解决的唯一问题是如何从工作者内部更新UI。有很多方法可以做到这一点 - 使用Control.Invoke/BeginInvokeSynchronizationContext等,但TPL的首选方法是传递和使用IProgress<T>接口。不要被名称所欺骗 - 接口是带有一些数据的回调的抽象。根据文档

,有一个标准的BCL提供的实现 - Progress<T>类具有以下行为
  

提供给使用ProgressChanged事件注册的构造函数或事件处理程序的任何处理程序都是通过构造实例时捕获的SynchronizationContext实例调用的。

即。完全适合UI更新方案。

尽管如此,以下是如何将其应用于您的代码。我们将使用IProgress<string>并调用Report方法并传递我们找到的每个文件/目录的全名 - 直接替换您的testTaskUpdateLabel来电。

private void button1_Click(object sender, EventArgs e)
{
    var progress = new Progress<string>(text => label4.Text = text);
    Task.Run(() =>
    {
        WalkDirectory(new DirectoryInfo(drive), progress);
    });
}

public bool WalkDirectory(DirectoryInfo directory, IProgress<string> progress)
{
    if (directory == null) throw new ArgumentNullException("directory");
    if (progress == null) throw new ArgumentNullException("progress");
    return WalkDirectories(directory, progress);
}

bool WalkDirectories(DirectoryInfo directory, IProgress<string> progress)
{
    // ...
    if (!(continueScan = WalkDirectories(subDirectory, progress)))
    // ...
    if (continueScan)
        progress.Report(directory.FullName);
    // ...
}

bool WalkFilesInDirectory(DirectoryInfo directory, IProgress<string> progress)
{
    // ...
    try
    {
        progress.Report(file.FullName);
    }
    // ...
}

答案 2 :(得分:0)

我通过使walkDirectory,walkDirectories和WalkFiles方法异步来实现它。因此在调用testUpdate和testUpdateLabel方法之前使用await关键字。这样,在搜索运行时,使用搜索结果更新列表视图,而不会阻止UI线程。 I.E.用户可以在找到他正在搜索的文件时取消搜索。