惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
P
Privacy & Cybersecurity Law Blog
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cisco Blogs
博客园 - 司徒正美
L
LINUX DO - 热门话题
D
Docker
M
MIT News - Artificial intelligence
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
Jina AI
Jina AI
Last Week in AI
Last Week in AI
Security Latest
Security Latest
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
A
Arctic Wolf
小众软件
小众软件
T
Threat Research - Cisco Blogs
Know Your Adversary
Know Your Adversary
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
腾讯CDC
Google DeepMind News
Google DeepMind News
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
I
Intezer
NISL@THU
NISL@THU
A
About on SuperTechFans
爱范儿
爱范儿
C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
G
Google Developers Blog
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Cyberwarzone
Cyberwarzone
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
Latest news
Latest news

博客园 - dalgleish

C# Avalonia 23- OpenGL- 例子通用类 C# Avalonia 22- SoundAndVideo- SpeechVoiceTest C# Avalonia 22- SoundAndVideo- SpeechRecognition C# Avalonia 22- SoundAndVideo- SpeechSynthesis C# Avalonia 22- SoundAndVideo- CodePlayback C# Avalonia 22- SoundAndVideo- SoundPlayerTest C# Avalonia 21- MenusAndToolbars- RibbonTest C# Avalonia 21- MenusAndToolbars- ProportionalStatusBar C# Avalonia 21- MenusAndToolbars- BasicToolbar C# Avalonia 21- MenusAndToolbars- ToolBar/Ribbon开源项目介绍和修复 C# Avalonia 21- MenusAndToolbars- SidebarMenu C# Avalonia 21- MenusAndToolbars- MixedMenus C# Avalonia 20 - WindowsMenu- 魔改Hyperlink - 使用例子 C# Avalonia 20 - WindowsMenu- 魔改Hyperlink C# Avalonia 20 - WindowsMenu- WebViewTest C# Avalonia 20 - WindowsMenu- WebView C# Avalonia 20 - WindowsMenu- ModernWindowTest C# Avalonia 20 - WindowsMenu- ModernWindow C# Avalonia 20 - WindowsMenu- TransparentWithShapes C# Avalonia 20 - WindowsMenu- TransparentBackground C# Avalonia 20 - WindowsMenu- OpenFileTest C# Avalonia 20 - WindowsMenu- SavePostion C# Avalonia 20 - WindowsMenu- CenterScreen C# Avalonia 19- DataBinding- DataGridGrouping C# Avalonia 19- DataBinding- BoundTreeView C# Avalonia 19- DataBinding- CustomListViewTest
C# Avalonia 19- DataBinding- DirectoryTreeView
dalgleish · 2026-02-18 · via 博客园 - dalgleish

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;
        }
    }
}

运行效果

image