C# 当最小化到下一级文件夹时,TreeView展开仍需要一段时间
我有以下代码,当用户展开treenode时,使用系统中的文件夹构建TreeViewC# 当最小化到下一级文件夹时,TreeView展开仍需要一段时间,c#,winforms,treeview,C#,Winforms,Treeview,我有以下代码,当用户展开treenode时,使用系统中的文件夹构建TreeView protected override void OnBeforeExpand(TreeViewCancelEventArgs e) { if (!_expandedCache.Contains((string)e.Node.Tag)) { BeginUpdate(); ShellFileGetInfo.FolderIcons fi; IEnumer
protected override void OnBeforeExpand(TreeViewCancelEventArgs e)
{
if (!_expandedCache.Contains((string)e.Node.Tag))
{
BeginUpdate();
ShellFileGetInfo.FolderIcons fi;
IEnumerable<string> dirs;
string path;
string currentPath;
_expandedCache.Add((string)e.Node.Tag);
TreeNode n;
foreach (TreeNode node in e.Node.Nodes)
{
try
{
path = (string)node.Tag;
dirs = Directory.EnumerateDirectories(path).OrderBy(d => d).Select(d => d.Split(Path.DirectorySeparatorChar).Last());
foreach (string dir in dirs)
{
currentPath = Path.Combine(path, dir);
if (File.Exists(Path.Combine(currentPath, "desktop.ini")) == true)
{
fi = ShellFileGetInfo.GetFolderIcon(currentPath, false);
ImageList.Images.Add(fi.closed);
ImageList.Images.Add(fi.open);
n = node.Nodes.Add(currentPath, dir, ImageList.Images.Count - 2, ImageList.Images.Count - 1);
n.Tag = currentPath;
}
else
{
n = node.Nodes.Add(currentPath, dir, 0, 1);
n.Tag = currentPath;
}
}
}
catch (UnauthorizedAccessException)
{
}
}
EndUpdate();
}
base.OnBeforeExpand(e);
}
为了让节点显示它是可扩展的,我必须以至少1个额外级别的深度加载到treeview中。因此,对于“c:\windows\”我需要加载system32,等等。当用户展开“windows”时,在OnBeforeExpand中,我需要填充所有子文件夹的子文件夹,使它们看起来是可展开的。为了防止在重新展开时加载树内容(当用户折叠窗口并重新展开窗口时),我缓存了在某个点已经展开的树节点列表。(这显然会对未来产生影响,比如如果用户在windows资源管理器中添加一个文件夹,它不会显示出来,但这是另一回事)
在获取特殊图标时,我发现最便宜的方法是对包含名为“desktop.ini”的文件的文件夹只使用SHGetFileInfo
p/invoke
我的问题是,无论我做什么,我都不能让这个树视图在任何合理的标准内运行。展开“Windows”树需要9秒,展开“inetpub”需要4秒,而“inetpub”只有4个文件夹。我相信速度减慢是由于未经授权的访问异常
造成的,我无法在不遇到该异常的情况下枚举目录
正如您所看到的,从视觉上看,它的操作与预期相符,但扩展某些文件夹需要很长的时间(比windows资源管理器长得多)。如您所见,初始视图的加载时间约为200毫秒(仍然很慢,但可以承受)
填充10个测试最多需要8秒,最差14秒-windows资源管理器是即时的
我可以做些什么来进一步提高此功能的性能。。。因此,这是可行的使用,不比Windows资源管理器的版本差 文件系统中存在试图在树中动态添加的数据。 根据操作系统和处理器的活动,以文件模式访问数据有时可能会减慢速度。 若您可以在某个数据库中移动数据,并通过从数据库中提取数据在树中添加节点,那个么速度会加快 您可以在SQLSERVER中的varbinary数据类型中将图像添加到数据库中
甚至Windows资源管理器也使用相同的技术。我更喜欢在最低级别访问数据,即Windows资源管理器用于获取图标的相同机制。我实际上能够将其缩小到此处详述的范围:。文件访问最慢的部分是出于任何原因访问文件系统。你建议建立我自己的目录是不可行的,因为以目前的速度需要数百小时(使用目前我能找到的最快的pinvoke+文件检查方法)-考虑到文件夹图标可能会改变,这是不可行的长期。理想的解决方案是以与windows在explorer.exe中完全相同的方式访问这些信息(不像!)。
public void SetRoot(string path)
{
_expandedCache = new List<string>();
Tag = path;
BeginUpdate();
ShellFileGetInfo.FolderIcons fi;
IEnumerable<string> dirs;
string currentPath;
TreeNode n;
dirs = Directory.EnumerateDirectories(path).OrderBy(d => d).Select(d => d.Split(Path.DirectorySeparatorChar).Last());
foreach (string dir in dirs)
{
currentPath = Path.Combine(path, dir);
if (File.Exists(Path.Combine(currentPath, "desktop.ini")) == true)
{
fi = ShellFileGetInfo.GetFolderIcon(currentPath, false);
ImageList.Images.Add(fi.closed);
ImageList.Images.Add(fi.open);
n = Nodes.Add(currentPath, dir, ImageList.Images.Count - 2, ImageList.Images.Count - 1);
n.Tag = currentPath;
}
else
{
n = Nodes.Add(currentPath, dir, 0, 1);
n.Tag = currentPath;
}
}
foreach (TreeNode node in Nodes)
{
path = (string)node.Tag;
try
{
dirs = Directory.EnumerateDirectories(path).OrderBy(d => d).Select(d => d.Split(Path.DirectorySeparatorChar).Last());
foreach (string dir in dirs)
{
currentPath = Path.Combine(path, dir);
if (File.Exists(Path.Combine(currentPath, "desktop.ini")) == true)
{
fi = ShellFileGetInfo.GetFolderIcon(currentPath, false);
ImageList.Images.Add(fi.closed);
ImageList.Images.Add(fi.open);
n = node.Nodes.Add(currentPath, dir, ImageList.Images.Count - 2, ImageList.Images.Count - 1);
n.Tag = currentPath;
}
else
{
n = node.Nodes.Add(currentPath, dir, 0, 1);
n.Tag = currentPath;
}
}
}
catch (UnauthorizedAccessException)
{
}
}
EndUpdate();
}