我有以下代码,当用户展开treenode时,使用系统中的文件夹构建TreeView。
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);
}
设置初始TreeView的代码是通过我的SetRoot
方法完成的,如下所示:
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();
}
为了让节点显示它是可扩展的,我必须在树视图中加载至少1个额外的深度。所以对于“c:\ windows \”我需要加载system32等。当用户扩展“Windows”时,在OnBeforeExpand中,我需要填充所有子文件夹的子文件夹,使它们看起来是可扩展的。为了防止在重新扩展时加载树内容(当用户折叠Windows并重新扩展Windows时),我会缓存已经在某些时候展开的TreeNodes列表。 (这显然会产生未来的影响,例如,如果用户在Windows资源管理器中添加了一个文件夹,它没有显示,但这是一个不同的故事)。
在获取特殊图标时,我发现最简单的方法是将SHGetFileInfo
p / invoke仅用于包含名为“desktop.ini”的文件的文件夹。
我的问题是,无论我做什么,我都无法在任何合理的标准内执行此TreeView。扩展“Windows”树需要9秒,而扩展只有4个文件夹的“inetpub”需要4秒。我认为减速是由于UnauthorizedAccessException
,我无法在不遇到这些情况的情况下看到枚举目录。
正如您所见,视觉上它正在按预期运行,但扩展一些文件夹需要很长时间(比Windows资源管理器长得多)。您看到的初始视图需要大约200毫秒才能加载(仍然很慢,但可以忍受)
充其量只花了8秒,最糟糕的是14次,超过10次测试填充 - Windows资源管理器是即时的
我可以做些什么来进一步提高性能? ...这样可以使用,而不是比Windows资源管理器的版本差!
答案 0 :(得分:1)
尝试在树中动态添加的数据存在于文件系统中。 在文件模式下访问数据有时可能会降低速度,具体取决于操作系统和处理器的活动。 如果您可以在某个数据库中移动数据,并通过从数据库中提取数据在树中添加节点,它将加速。
您可以在SQLSERVER中以varbinary数据类型在数据库中添加图像。
即使Windows资源管理器也使用相同的技术。