DirectoryTreeView.axaml代码
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="300" Width="300" x:Class="AvaloniaUI.DirectoryTreeView" Title="DirectoryTreeView"> <Grid Margin="3"> <TreeView Name="treeFileSystem"/> </Grid> </Window>
DirectoryTreeView.axaml.cs代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using System;
using System.Collections.Generic;
using System.IO;
namespace AvaloniaUI;
public partial class DirectoryTreeView : Window
{
private static readonly object Placeholder = new();
public DirectoryTreeView()
{
InitializeComponent();
BuildTree();
}
private void BuildTree()
{
treeFileSystem.Items.Clear();
foreach (var drive in DriveInfo.GetDrives())
{
if (!drive.IsReady)
continue;
var item = CreateItem(drive.Name, drive);
AddPlaceholder(item);
treeFileSystem.Items.Add(item);
}
}
private TreeViewItem CreateItem(string header, object tag)
{
var item = new TreeViewItem
{
Header = header,
Tag = tag
};
item.Expanded += ItemExpanded;
return item;
}
private void ItemExpanded(object? sender, RoutedEventArgs e)
{
if (sender is not TreeViewItem item)
return;
// 只在第一次展开(且存在占位符)时加载
if (item.Items.Count != 1 || !ReferenceEquals(item.Items[0], Placeholder))
return;
item.Items.Clear();
var dir = GetDirectoryInfo(item.Tag);
if (dir is null)
return;
foreach (var subDir in SafeEnumerateDirectories(dir))
{
var child = CreateItem(subDir.Name, subDir);
// 只有确实还有子目录,才显示展开箭头(放占位符)
if (HasSubdirectories(subDir))
AddPlaceholder(child);
item.Items.Add(child);
}
}
private static DirectoryInfo? GetDirectoryInfo(object? tag)
{
if (tag is DriveInfo drive)
return drive.RootDirectory;
if (tag is DirectoryInfo dir)
return dir;
return null;
}
private static void AddPlaceholder(TreeViewItem item)
{
item.Items.Add(Placeholder);
}
private static IEnumerable<DirectoryInfo> SafeEnumerateDirectories(DirectoryInfo dir)
{
IEnumerator<DirectoryInfo>? enumerator = null;
try
{
enumerator = dir.EnumerateDirectories().GetEnumerator();
}
catch
{
yield break;
}
using (enumerator as IDisposable)
{
while (true)
{
DirectoryInfo current;
try
{
if (!enumerator.MoveNext())
break;
current = enumerator.Current;
}
catch
{
// 某个子目录读不了:跳过,不影响整层
continue;
}
yield return current;
}
}
}
private static bool HasSubdirectories(DirectoryInfo dir)
{
try
{
using var e = dir.EnumerateDirectories().GetEnumerator();
return e.MoveNext();
}
catch
{
return false;
}
}
}
运行效果

浙公网安备 33010602011771号