好的,我有一个TreeView作为
Windows的目录树.我有它加载所有目录并正常运行,但它正在暂停我的GUI,同时它加载了很多孩子的目录.我正在尝试实现多线程,但我是新手,并且没有运气.
这就是我对TreeView的看法:
private readonly object _dummyNode = null;
public MainWindow()
{
InitializeComponent();
foreach (string drive in Directory.GetLogicalDrives())
{
DriveInfo Drive_Info = new DriveInfo(drive);
if (Drive_Info.IsReady == true)
{
TreeViewItem item = new TreeViewItem();
item.Header = drive;
item.Tag = drive;
item.Items.Add(_dummyNode);
item.Expanded += folder_Expanded;
TreeViewItemProps.SetIsRootLevel(item, true);
Dir_Tree.Items.Add(item);
}
}
}
private void folder_Expanded(object sender, RoutedEventArgs e)
{
TreeViewItem item = (TreeViewItem)sender;
if (item.Items.Count == 1 && item.Items[0] == _dummyNode)
{
item.Items.Clear();
try
{
foreach (string dir in Directory.GetDirectories(item.Tag as string))
{
DirectoryInfo tempDirInfo = new DirectoryInfo(dir);
bool isSystem = ((tempDirInfo.Attributes & FileAttributes.System) == FileAttributes.System);
if (!isSystem)
{
TreeViewItem subitem = new TreeViewItem();
subitem.Header = tempDirInfo.Name;
subitem.Tag = dir;
subitem.Items.Add(_dummyNode);
subitem.Expanded += folder_Expanded;
subitem.ToolTip = dir;
item.Items.Add(subitem);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
每当我展开具有大量子目录的目录时,该程序似乎被冻结几秒钟.我想在处理时显示加载消息或动画,但我不知道如何从多线程开始.我知道我必须使用TreeView的Dispatcher.BeginInvoke方法,但除此之外,我有点迷失.
任何帮助将不胜感激!!!
最佳答案 启动异步过程的最简单方法之一是使用带有BeginInvoke的匿名委托.作为示例,您可以将构造函数中的代码移动到单独的方法(比如RenderTreeView),然后异步调用它以开始新线程,如下所示:
Action action = RenderTreeView;
action.BeginInvoke(null, null);
解决这个问题的方法是,每当您与异步进程中的任何UI元素进行交互时,您都需要重新加入主UI线程,否则您将获得有关跨线程访问的异常.这也是相对直接的.
在Windows窗体中它是:
if (InvokeRequired)
Invoke(new MethodInvoker({item.Items.Add(subitem)}));
else
item.Items.Add(subitem);
在WPF中它是:
if (!Dispatcher.CheckAccess())
Dispatcher.Invoke(new Action(() => item.Items.Add(subitem)));
else
item.Items.Add(subitem);
您确实需要分解代码以使其在方法方面更加灵活.目前,所有内容都捆绑在一个方法中,这使得很难处理和重新考虑异步进程.
更新在这里你去:)
public partial class MainWindow : Window
{
private readonly object dummyNode = null;
public MainWindow()
{
InitializeComponent();
Action<ItemCollection> action = RenderTreeView;
action.BeginInvoke(treeView1.Items, null, null);
}
private void RenderTreeView(ItemCollection root)
{
foreach (string drive in Directory.GetLogicalDrives())
{
var driveInfo = new DriveInfo(drive);
if (driveInfo.IsReady)
{
CreateAndAppendTreeViewItem(root, drive, drive, drive);
}
}
}
private void FolderExpanded(object sender, RoutedEventArgs e)
{
var item = (TreeViewItem) sender;
if (item.Items.Count == 1 && item.Items[0] == dummyNode)
{
item.Items.Clear();
var directory = item.Tag as string;
if (string.IsNullOrEmpty(directory))
{
return;
}
Action<TreeViewItem, string> action = ExpandTreeViewNode;
action.BeginInvoke(item, directory, null, null);
}
}
private void ExpandTreeViewNode(TreeViewItem item, string directory)
{
foreach (string dir in Directory.GetDirectories(directory))
{
var tempDirInfo = new DirectoryInfo(dir);
bool isSystem = ((tempDirInfo.Attributes & FileAttributes.System) == FileAttributes.System);
if (!isSystem)
{
CreateAndAppendTreeViewItem(item.Items, tempDirInfo.Name, dir, dir);
}
}
}
private void AddChildNodeItem(ItemCollection collection, TreeViewItem subItem)
{
if (Dispatcher.CheckAccess())
{
collection.Add(subItem);
}
else
{
Dispatcher.Invoke(new Action(() => AddChildNodeItem(collection, subItem)));
}
}
private void CreateAndAppendTreeViewItem(ItemCollection items, string header, string tag, string toolTip)
{
if (Dispatcher.CheckAccess())
{
var subitem = CreateTreeViewItem(header, tag, toolTip);
AddChildNodeItem(items, subitem);
}
else
{
Dispatcher.Invoke(new Action(() => CreateAndAppendTreeViewItem(items, header, tag, toolTip)));
}
}
private TreeViewItem CreateTreeViewItem(string header, string tag, string toolTip)
{
var treeViewItem = new TreeViewItem {Header = header, Tag = tag, ToolTip = toolTip};
treeViewItem.Items.Add(dummyNode);
treeViewItem.Expanded += FolderExpanded;
return treeViewItem;
}
}