WPF自定义TreeViewPlus控件二级及以上节点无法展开求助
我仔细梳理了你的代码,找到了几个可能导致二级节点无法展开的核心问题,下面一步步帮你修复:
1. 错误的子目录判断逻辑
你的构造函数里判断是否存在子目录的代码是:
If Not dir.EnumerateDirectories Is Nothing Then
这是典型的逻辑错误——dir.EnumerateDirectories()返回的是一个永远不会为Null的IEnumerable(Of DirectoryInfo),哪怕目录下没有子文件夹,它也是一个空的枚举集合,而非Nothing。这会导致不管目录有没有子文件夹,都强制添加一个空的TreeViewPlus项,不仅影响UI体验,还可能掩盖真正的加载问题。
修复判断逻辑,改为检查是否存在实际的子目录:
If dir.EnumerateDirectories().Any() Then
2. 静默捕获异常,无法排查问题
你的代码里所有异常都被Catch ex As Exception捕获,但没有任何日志输出或提示。如果二级目录存在权限限制(比如系统保护目录),EnumerateDirectories()会抛出异常,导致子节点无法加载,但你完全不知道发生了什么。
建议在捕获异常时添加调试日志,方便定位问题:
Catch ex As Exception System.Diagnostics.Debug.WriteLine($"加载目录 {dir.FullName} 失败: {ex.Message}") End Try
3. 确保Expanded事件可靠绑定
虽然VB.NET的Handles Me.Expanded理论上能绑定每个实例的事件,但动态创建控件时偶尔会出现事件绑定失效的情况。你可以手动绑定事件,替代Handles关键字,确保事件能稳定触发:
修改构造函数,添加手动事件绑定:
Public Sub New(dir As DirectoryInfo) Me.dir = dir ' 手动绑定Expanded事件 AddHandler Me.Expanded, AddressOf TreeViewPlus_Expanded Try If dir.EnumerateDirectories().Any() Then Me.Items.Add(New TreeViewPlus) End If Catch ex As Exception System.Diagnostics.Debug.WriteLine($"初始化目录 {dir.FullName} 失败: {ex.Message}") End Try End Sub
同时去掉事件方法的Handles Me.Expanded:
Private Sub TreeViewPlus_Expanded(sender As Object, e As RoutedEventArgs) ' ... 原有代码 ... End Sub
4. 优化节点Header设置逻辑
你目前在根节点外部设置Header,在二级节点的Expanded事件里设置Header,可以统一放在构造函数里,让代码更简洁清晰:
Public Sub New(dir As DirectoryInfo) Me.dir = dir AddHandler Me.Expanded, AddressOf TreeViewPlus_Expanded ' 直接在构造函数中设置Header Me.Header = dir.Name Try If dir.EnumerateDirectories().Any() Then Me.Items.Add(New TreeViewPlus) End If Catch ex As Exception System.Diagnostics.Debug.WriteLine($"初始化目录 {dir.FullName} 失败: {ex.Message}") End Try End Sub
这样初始化根节点时就不需要额外设置Header了:
For Each Drive As IO.DriveInfo In IO.DriveInfo.GetDrives Dim item As TreeViewPlus = New TreeViewPlus(Drive.RootDirectory) ' 移除这行冗余代码:item.Header = Drive.Name TRV_Arbre.Items.Add(item) Next
完整修复后的TreeViewPlus代码
Private Class TreeViewPlus Inherits TreeViewItem Public dir As IO.DirectoryInfo Public Sub New() End Sub Public Sub New(dir As DirectoryInfo) Me.dir = dir AddHandler Me.Expanded, AddressOf TreeViewPlus_Expanded Me.Header = dir.Name Try ' 正确判断是否存在子目录 If dir.EnumerateDirectories().Any() Then ' 添加空项显示展开箭头 Me.Items.Add(New TreeViewPlus) End If Catch ex As Exception System.Diagnostics.Debug.WriteLine($"初始化目录 {dir.FullName} 失败: {ex.Message}") End Try End Sub Private Sub TreeViewPlus_Expanded(sender As Object, e As RoutedEventArgs) Me.Items.Clear() Try For Each folder In dir.EnumerateDirectories() Dim item As TreeViewPlus = New TreeViewPlus(folder) item.Name = Text.RegularExpressions.Regex.Replace(folder.FullName, "[^a-zA-Z0-9]", "") Me.Items.Add(item) Next Catch ex As Exception System.Diagnostics.Debug.WriteLine($"加载子目录 {dir.FullName} 失败: {ex.Message}") End Try End Sub End Class
按照上面的修改,应该能解决二级及以上节点无法展开的问题。如果仍有异常,查看调试窗口的日志信息,就能快速定位具体原因了。
内容的提问来源于stack exchange,提问作者Benoit Bouckaert

