我编写了一个小程序,在整个syatem中搜索某种文件,搜索完成后会在列表视图中显示结果,但是当我运行此程序时,我的表单冻结,我无法做任何事情。
有人可以帮助我解决问题,下面是我编写的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using System.IO.Compression;
using System.Security.AccessControl;
namespace SearchAndZipUtility
{
public partial class MainForm : Form
{
private string _destFolder;
private string _sourceToSearch = @"E:\New Books";
private TaskScheduler schedular = TaskScheduler.Current;
private CancellationTokenSource _ct = new CancellationTokenSource();
private List<string> files = new List<string>();
private string _selectedFileType;
public MainForm()
{
InitializeComponent();
toolStripStatusInfo.Visible = false;
btnZip.Enabled = false;
}
protected override void OnLoad(EventArgs e)
{
// bind file types to combo box
PopulateComboList();
if (cmbFileTypes.Items.Count > 0)
{
cmbFileTypes.SelectedIndex = 0;
}
}
private void PopulateComboList()
{
cmbFileTypes.Items.AddRange(FileTypes.GetFileTypes());
}
private void btnDest_Click(object sender, EventArgs e)
{
DialogResult dr = folderBrowserDialog.ShowDialog();
if (dr == System.Windows.Forms.DialogResult.OK)
{
_destFolder = folderBrowserDialog.SelectedPath;
txtDestFolder.Text = _destFolder;
}
}
private void btnStartSearch_Click(object sender, EventArgs e)
{
toolStripStatusInfo.Visible = true;
btnStartSearch.Enabled = false;
fileListView.Items.Clear();
fileListView.Refresh();
_selectedFileType = cmbFileTypes.SelectedItem.ToString();
List<Task> taskList = new List<Task>();
DriveInfo[] drives = DriveInfo.GetDrives().Where(drive => drive.DriveType == DriveType.Fixed).ToArray();
try
{
foreach (DriveInfo d in drives)
{
DriveInfo dInfo = d;
//Task searchTask = Task.Factory.StartNew( () => { Fi}, _ct.Token, TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());
Task searchTask = Task.Factory.StartNew(() => { FindFiles(dInfo.RootDirectory, ref files); }
, _ct.Token, TaskCreationOptions.LongRunning
, TaskScheduler.FromCurrentSynchronizationContext());
System.Diagnostics.Trace.WriteLine("currently reading" + d.RootDirectory.FullName);
taskList.Add(searchTask);
searchTask.ContinueWith(PopulateResultList, TaskScheduler.FromCurrentSynchronizationContext());
}
Task.Factory.ContinueWhenAll(taskList.ToArray(), OnSearchCompleted, _ct.Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
finally
{
}
}
private void OnSearchCompleted(Task[] tasks)
{
// hide notifier label
toolStripStatusInfo.Visible = false;
btnStartSearch.Enabled = true;
btnZip.Enabled = true;
toolStripStatusLabel.Text = string.Format("Total files found: {0}", files.Count);
}
private List<string> SearchFiles()
{
// DirectoryInfo dirSource = new DirectoryInfo(_sourceToSearch);
_selectedFileType = cmbFileTypes.SelectedItem.ToString();
return files;
}
private void FindFiles(DirectoryInfo directoryInfo, ref List<string> files)
{
FileSystemAccessRule rule = new FileSystemAccessRule(System.Security.Principal.WindowsIdentity.GetCurrent().Name, FileSystemRights.FullControl, System.Security.AccessControl.AccessControlType.Allow);
try
{
foreach (DirectoryInfo d in directoryInfo.GetDirectories())
{
//d.GetAccessControl().ResetAccessRule(rule);
System.Diagnostics.Trace.WriteLine("currently reading> " + d.FullName);
FindFiles(d, ref files);
}
files.AddRange(directoryInfo.GetFiles(string.Format("*.{0}", _selectedFileType), SearchOption.AllDirectories).Select(finfo => finfo.FullName));
}
catch (UnauthorizedAccessException excep)
{
System.Diagnostics.Trace.WriteLine(excep.Message);
}
catch (Exception e)
{
return; // MessageBox.Show(e.Message);
}
}
private void PopulateResultList(Task searchedTask)
{
// fill up list view
fileListView.Items.AddRange(files.Select(fileName => new ListViewItem { Checked = true, Text = fileName }).ToArray());
toolStripStatusLabel.Text = string.Format("Total files found so far: {0}", files.Count);
}
private void btnZip_Click(object sender, EventArgs e)
{
}
}
}
答案 0 :(得分:1)
您正在使用当前任务计划程序启动任务,在这种情况下使用消息循环。
因此,当消息循环开始处理该任务时,它将阻塞直到完成。
尽量避免指定任务调度程序,它应该为您的任务启动新线程。
答案 1 :(得分:0)
您正在使用FindFiles
函数执行一些非常繁重的recursive处理。如果你从目录结构的某个低位开始,你可能会看到一些缓慢的处理......
根据您的需要,您可能无法避免这种情况。您可以尝试在第一次拨打FindFiles
之前和之后设置一个断点,看看这是否是问题区域。
答案 2 :(得分:0)
我怀疑您需要设置后台工作程序(或其他DoWork()
线程方案)。这是来自无法估量的Jon Skeet的an article,可能有所帮助。
答案 3 :(得分:0)
将以下代码行放在任何具有密集处理的循环中
Application.DoEvents();
这可以避免使用多个线程并保持表单响应。但是,您必须小心禁用/重新启用您不希望用户在作业运行时单击的任何按钮。
线程通常被认为是处理无响应的更好方法,但它们更复杂,所以这是一个很好的替代方法。
如果您将DoEvents添加到FindFiles方法,则可以删除Factory.StartNew并直接为每个任务调用FindFiles。