cmbDrives.DataSource = Environment.GetLogicalDrives();
我有这段代码可以在组合框中显示所有驱动器,并希望treeview
在comboboxselectionchanged
事件中显示所有驱动器的相关数据。
我怎样才能做到这一点?
以下代码通过利用后台工作程序来确保在文件夹遍历期间取得进展时 UI 保持响应,从而实现您想要的。
首先将 ComboBox、Treeview 和 BackgroundWorker 添加到您的设计图面。确保从使用事件视图的每个控件的“属性”窗口中添加以下代码中使用的事件。确保WorkerReportsProgress
将 BackgroundWorker 的属性设置为 true。
首先是 ComboBox SelectionIndexChanged 事件:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
this.comboBox1.Enabled = false;
this.backgroundWorker1.RunWorkerAsync(comboBox1.SelectedItem.ToString());
}
我们禁用组合框以防止在处理驱动器遍历时选择新值。然后我们启动 BackgroundWorker,将 SelectedItem 传递给它,我们假设它是一个有效的驱动器。
DoWork 事件采用具有 Argument 属性的 eventargs,该属性包含我们通过调用 RunWorkerAsync 提供的值。当我们现在在一个非 UI 线程上时,我们需要一些技巧来更新 UI。后台工作人员可以使用其 ReportProgress 方法来做到这一点。它需要一个整数,通常用于我们有多远和一个可选的用户状态。我们使用这两个来指示我们所处的状态,并提供需要在 TreeView 上添加或更新的 TreeNode。然后它调用GetDirectoryNodes
进行目录遍历。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
TreeNode node = new TreeNode(e.Argument.ToString());
backgroundWorker1.ReportProgress(0, node);
GetDirectoryNodes(e.Argument.ToString(), node);
}
每次我们有一个 TreeNode(或 TreeNode 的元组)时都会调用 ProgressChanged,因此我们可以在 UI 线程中将节点添加到 TreeView 或其节点之一。不是用来显示我们有多远,ProgressPercentage
而是用来区分初始状态和遍历状态。
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
switch (e.ProgressPercentage)
{
case 0:
// we have s TreeNode, this is our root.
treeView1.Nodes.Add((TreeNode) e.UserState);
break;
case 1:
// we get a tuple, the parent and it's intended child.
var tup = (Tuple<TreeNode,TreeNode>) e.UserState;
tup.Item1.Nodes.Add(tup.Item2);
break;
default:
break;
}
}
完成后(即遍历每个文件夹),我们再次启用组合框,以便我们可以选择一个新驱动器。
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.comboBox1.Enabled = true;
}
为了遍历目录树,我使用了一个递归函数(受到Chris Ballard 的回答的启发,一旦它具有准备添加到 TreeView 的 TreeNode,就会 调用 BackgroundWorkersReportProgress
方法。请注意我如何使用 Tuple 作为状态对象来保存要添加的父项和子项,但该特定操作留给 UI 线程上的 ProgressChanged 事件。
private void GetDirectoryNodes(string path, TreeNode node)
{
try
{
var subDirs = Directory.GetDirectories(path);
foreach (string p in subDirs)
{
var subnode = new TreeNode(p);
backgroundWorker1.ReportProgress(
1,
new Tuple<TreeNode, TreeNode>(
node, subnode
));
GetDirectoryNodes(p, subnode); // recursive!
}
}
catch (Exception exp)
{
var subnode = new TreeNode(path+"\\error");
subnode.ToolTipText = exp.Message;
backgroundWorker1.ReportProgress(
1,
new Tuple<TreeNode, TreeNode>(
node, subnode
));
}
}