# Fluid 文件资源管理器(WinUI 3 重构版) 用 **Windows App SDK / WinUI 3** 从零实现的 Windows 11 文件资源管理器替代品。 视觉与布局对齐原版(标签栏在标题栏内、Mica、命令栏、面包屑地址栏、导航窗格、详情/图标视图、状态栏), 但针对原版被吐槽最多的几个痛点做了结构性改造。 > 只用 **Windows 11 原生那一套**:WinUI 3 自带控件(NavigationView 风格侧边栏用 TreeView、TabView、BreadcrumbBar、AutoSuggestBox、InfoBar、ContentDialog…)、 > **Segoe Fluent Icons** 官方图标字体、**外壳原版文件图标**(`SHGetFileInfo` / `IShellItemImageFactory`,即资源管理器显示的同一批 imageres.dll 图标)、 > 以及系统自带的 Mica 材质与 WinUI 原生动画。**没有引入任何第三方 UI/图标/动画库**。 --- ## 1. 直接运行 ```powershell dotnet build E:\deepseek\FluidExplorer\FluidExplorer.csproj -c Debug E:\deepseek\FluidExplorer\bin\Debug\net8.0-windows10.0.26100.0\win-x64\FluidExplorer.exe ``` - 目标框架 `net8.0-windows10.0.26100.0`,x64,非打包(`WindowsPackageType=None`)+ **Windows App SDK 自包含**, 因此不需要预装 Windows App SDK 运行时,双击 exe 即可。 - 本机 NuGet 离线(`nuget.config` 里 ``):所有依赖已在全局包缓存中,可直接还原。 依赖仅 `Microsoft.WindowsAppSDK 2.2.0` 与 `CommunityToolkit.Mvvm 8.4.2`(后者只用于减少 `INotifyPropertyChanged` 样板代码)。 - 设置文件:`%LOCALAPPDATA%\FluidExplorer\settings.json`(写入失败时退回程序目录)。 - 启动日志:程序目录下 `startup.log`(用于定位启动期异常)。 --- ## 2. 针对原版痛点的改造 | 原版痛点 | 本实现的做法 | |---|---| | **搜索慢/搜不到**(原版走 Windows Search 索引,往往等半天甚至永远"正在搜索") | Everything 式 **NTFS 索引**:`FSCTL_ENUM_USN_DATA` 直读 MFT 全集 + 原始 MFT 解析取真实大小/时间 + `FSCTL_READ_USN_JOURNAL` 增量监听;查询是内存并行扫描,**20 万条目下 0.3–9 ms**(见 §5)。没有索引时自动退化为可取消的实时扫描,并在界面上明确标注"实时扫描",绝不假装在搜 | | **搜索框必须回车、没有即时反馈** | 键入即搜(110 ms 防抖)+ 搜索框下拉即时建议 + 结果区实时显示"N 项结果 · X 毫秒 · 数据来源" | | **搬文件很麻烦**(开两个窗口来回拖) | ① **双窗格**(Ctrl+Shift+D,中间可拖动分隔条)② 跨窗格剪贴板 ③ 拖到文件夹行/侧边栏即可移动(按住 Ctrl 复制)④ "移动到/复制到"以外的批量操作统一进队列 | | **复制/移动卡死、无法暂停/取消** | 独立**文件操作引擎**:后台队列、**可暂停/继续/取消**、字节级进度 + 速度 + 剩余时间、失败重试(100/300/900 ms)、单文件失败不中断整批、长路径(`\\?\`)支持、同卷移动走 `File.Move`(1000 个文件 15 ms) | | **覆盖冲突弹系统模态框、还打断操作** | 应用内冲突对话框(保留两者/替换/跳过 + "对后续所有冲突应用"),作业在等待用户选择时**保持运行态、UI 完全不卡** | | **误操作无法挽回** | **Ctrl+Z 一步撤销**:移动/重命名搬回原位;删除默认进回收站并记录 `$I`→`$R` 映射,撤销即从回收站还原(不依赖系统弹窗) | | **打开大文件夹/网络盘就"无响应"** | 枚举走 `FileSystemEnumerable`(底层 NtQueryDirectoryFile 批量缓冲,一次拿回名称+属性+大小+时间),**分批回调**(首批立刻上屏)、全程可取消、错误只在 InfoBar 提示不阻塞;属性列的真类型名走注册表并缓存 | | **状态栏信息少** | 底部状态栏常驻:项目数 / 选中项数与合计体积 / 索引进度与条数 / 一键建索引 / 视图切换 / **操作队列入口** | | **深浅色与强调色不跟随** | 全部颜色取自 WinUI 内置主题资源(不写死任何色值),`ElementTheme.Default` + `MicaBackdrop` 跟随系统;标题栏按钮颜色随主题切换;设置里可手动覆盖为浅/深色 | | **动画要么没有要么过度** | 只用 WinUI 原生动画(列表项增删、悬停/选中反馈、TabView、对话框、Mica 过渡);设置里可一键关闭(内部用 `Timeline.AllowDependentAnimations` 总开关),不额外叠加自造动效 | 其他对齐原版的细节:真实路径面包屑(此电脑 › 本地磁盘 › …)、侧边栏(主页/图库/快速访问/此电脑/网络/回收站,可展开、跟随当前路径高亮)、 按文件夹记住视图方式与排序(写入 `settings.json`)、"名称"列用系统 `StrCmpLogicalW` 自然排序(文件2 排在 文件10 前)、文件夹恒排在文件前、 显示/隐藏隐藏项与扩展名、**系统原版右键菜单**(外壳 `IContextMenu`,第三方扩展条目也在)。 键盘:`Ctrl+T/W/Tab` 标签页、`Ctrl+Shift+D` 双窗格、`Alt+←/→/↑` 前进后退上级、`Backspace` 上级、`F5` 刷新、`F2` 重命名、 `Delete`/`Shift+Delete` 删除/彻底删除、`Ctrl+X/C/V`、`Ctrl+Shift+C` 复制路径、`Ctrl+Shift+N` 新建文件夹、`Ctrl+Z` 撤销、`Ctrl+F` 聚焦搜索、`Ctrl+L` 编辑地址。 --- ## 3. 代码结构 ``` FluidExplorer/ ├─ App.xaml(.cs) 应用入口、启动阶段日志、全局异常兜底 ├─ MainWindow.xaml(.cs) 窗口外壳:Mica、扩展标题栏、标题栏按钮配色、快捷键、冲突对话框 ├─ Views/ │ ├─ ShellView.xaml(.cs) 标签栏(位于标题栏区域内)+ 操作队列面板 │ ├─ ExplorerTabView.xaml(.cs) 单/双窗格布局与分隔条 │ ├─ ExplorerPaneView.xaml(.cs) 一个浏览窗格:命令栏 / 地址栏 / 导航窗格 / 内容区 / 状态栏 │ └─ SettingsDialog.xaml(.cs) 设置 ├─ ViewModels/ │ ├─ MainViewModel.cs 标签页、侧边栏、索引状态、作业快照、设置 │ ├─ ExplorerTabViewModel.cs 标签页 = 1~2 个窗格 │ ├─ ExplorerPaneViewModel.cs 导航状态机:枚举、排序、搜索、选择、文件操作、回收站、图库 │ ├─ JobRowViewModel.cs UI 线程的作业快照(作业在后台线程更新,不能直接绑 UI) │ └─ SidebarNode.cs 侧边栏节点 / 面包屑段 / 搜索结果行 ├─ Models/ FileEntry / ExplorerItem / FolderListing / 排序与视图枚举 ├─ Navigation/ 位置模型(本机/图库/此电脑/回收站/驱动器/路径)+ 前进后退历史 ├─ Services/ │ ├─ AppServices.cs 组合根 │ ├─ AppSettings.cs 设置持久化(含按文件夹视图状态) │ ├─ FileSystem/ 快速枚举(NtQueryDirectoryFile 批量缓冲)+ 路径工具 │ ├─ Search/ 查询语法解析、搜索门面、NTFS 索引(Usn/:MFT 解析、名字池、索引存储、通配符) │ ├─ Icons/ 外壳原版图标与缩略图(SHGetFileInfo / IShellItemImageFactory,LRU + 同键合并) │ ├─ Operations/ 文件操作队列引擎(复制/移动/删除/重命名/撤销/回收站定位) │ ├─ ItemVisuals/ 列表行的图标/缩略图按需加载(并发上限 + 去重) │ └─ Shell/ 外壳能力:已知文件夹、类型名、打开/属性/剪贴板、回收站视图、原版右键菜单 ├─ Themes/ Styles.xaml(尺寸/样式)、Glyphs.xaml(Segoe Fluent Icons 码点) └─ Helpers/ DispatcherQueue 异步封装、值转换器 ``` 设计要点: 1. **接口先冻结再并行开发**:`IFileIndex` / `IIconService` / `IFileOperationService` / `IFileSystemService` 先定义, 索引、图标、操作三个模块独立实现(互不依赖),最后由 `AppServices` 装配。 2. **UI 线程零阻塞**:所有文件系统交互都是异步 + 可取消;集合更新经 `DispatcherQueue` 分批提交。 3. **后台对象不直接绑 UI**:作业在后台线程更新,界面绑的是 250 ms 刷新的 UI 线程快照(`JobRowViewModel`)。 4. **失败降级而不是崩溃**:假索引不可用时搜索自动退化;外壳取图失败返回 null 并回退到扩展名图标;启动异常写入 `startup.log`。 --- ## 4. 搜索语法(对齐 Everything 习惯) ``` keyword 名称包含(大小写不敏感,多个词 = AND) "两个 词" 带空格的短语 !keyword 排除 *.json / pre* 通配符 ext:log;txt 扩展名(可多值) size:>100mb 大小(kb/mb/gb,支持 > < =) dm:today / dm:7d 修改时间(today/yesterday/thisweek/thismonth/thisyear/Nd/Nh/Nw 或具体日期) dc:today 创建时间(需要索引提供创建时间,当前版本未启用) folder: / file: 只看文件夹 / 只看文件 path:Windows 在完整路径中匹配 ``` --- ## 5. 验证情况(都基于本机实测,不采信"应该能用") **实测通过** - 工程编译:`0 error`;XAML 全部编译为 xbf(含主题字典)。 - 端到端启动:进程存活、窗口标题「文件资源管理器」、UI Automation 树确认——标签栏在标题栏区域内(系统按钮区已正确让位)、 命令栏 12 个按钮、地址栏(后退/前进/上级/刷新 + 2 段面包屑 + 搜索框)、导航窗格 16 个节点、 详情视图 4 个列头(名称/修改日期/类型/大小)、**真实列出 107 行文件**、状态栏与操作队列入口在位。 - 搜索:通过 UI Automation 向搜索框写入关键字,界面返回结果行并显示「N 项结果 · X 毫秒 · 数据来源」。 - 文件操作引擎(独立探针,62/62 断言 PASS):300 MB 复制的字节级进度;**暂停 1 秒增长 0 字节**;取消保留已完成部分; 同卷移动 1000 文件 **15 ms**(零字节流量);`KeepBoth/Replace/Skip/Ask+ApplyToAll` 全部正确; 308→312 字符长路径复制/移动成功;跨卷移动可撤销;永久删除不入撤销栈。 - NTFS 索引(独立探针,走生产代码路径):20 万条目合成数据集 **77 字节/条**; 查询 `*.json` 3.3 ms、`ext:log` 1.4 ms、`size:>100mb` 0.66 ms、`dm:today` 0.3 ms、`path:Windows` 9.3 ms; 2000 条路径还原 1.66 ms;增量(创建/改名/删除)与墓碑正确;大小未知的条目不会被 `size:` 误判为 0 字节。 过程中修掉一个会**静默丢 64% 结果**的扩容 bug(名字池被换新导致老记录名字失效)。 - 图标:`.txt/.exe/目录/驱动器` 均取到系统原生图标(32×32 原生尺寸、真 alpha);`shell:RecycleBinFolder` 等外壳对象正常; 图片缩略图 256×160 正常;1000 次扩展名取图 86 ms;300 次取图后 GDI/USER 句柄**零增长**。 **已知限制(不隐瞒)** - **当前会话没有管理员权限**:`CreateFile(@"\\.\C:")` 被拒(`FSCTL_*` 返回 `ERROR_INVALID_FUNCTION`), 因此 NTFS 索引在本机本次验证中走的是 `RequiresElevation` 分支;界面状态栏会提示并可一键「以管理员身份重启」。 索引本身的正确性用同一份生产代码 + 合成数据集验证(见上)。**要拿到真实全盘索引,请以管理员身份运行一次。** - 非管理员降级模式下文件大小全部为"未知"(USN 记录本身不含 size,真实大小依赖原始 MFT 解析),此时 `size:` 过滤会偏宽松。 - 拖放到**其他应用程序**、拖出标签新建窗口、网络邻居枚举为简化实现;图库依赖索引(无索引时给提示而非空列表)。 - 缩略图/图标语义、字体字形只做了"码点在字体中存在"的校验(60/60 存在,不会出现方框), 但**字形语义未经人眼确认**(本会话的模型不能读图),个别按钮图标若观感不佳可直接改 `Themes/Glyphs.xaml` 里的码点。 --- ## 6. 复现验证 ```powershell # 编译 dotnet build E:\deepseek\FluidExplorer\FluidExplorer.csproj -c Debug # 启动 + UI 自动化结构检查 + 截图(截图落在 E:\deepseek\artifacts\shell_window.png) powershell -NoProfile -ExecutionPolicy Bypass -File E:\deepseek\tools\smoke_test.ps1 # 字形存在性校验(Segoe Fluent Icons) powershell -NoProfile -ExecutionPolicy Bypass -File E:\deepseek\tools\check_glyphs.ps1 ```