基于 Avalonia UI + .NET 8 的 Windows 网络管理器,Material Design 3 风格,支持进程级流量监控与防火墙控制。
Windows Network Manager 是一个现代化的 Windows 桌面工具,用于实时监控所有运行进程的网络活动,并通过 Windows 防火墙 API 精细控制每个进程的联网权限。
- 进程树 — WMI 查询父子关系,树状展示所有进程及子进程,默认折叠,点击展开
- 实时流量 — 全局网络带宽 + TCP/UDP 连接数按比例分配,显示每个进程的上下行速度与累计流量
- 防火墙控制 — 5 级联网权限:🚫临时禁止 / ♾永久禁止 / ⬆仅上传 / ⬇仅下载 / ✅允许全部
- 4 种排序 — 上传速度 ↓ / 下载速度 ↓ / 上传总量 ↓ / 下载总量 ↓
- 进程图标 —
System.Drawing提取 exe 原生图标 - Hosts 编辑器 — 一键打开系统 hosts 文件
- Material Design 3 — 完整的 M3 色彩 Token 系统、组件样式、深色/浅色切换动画
- 单文件 exe —
dotnet publish -p:PublishSingleFile=true打包为独立可执行文件
| 亮色主题 | 暗色主题 |
|---|---|
| (运行截图) | (运行截图) |
| 项目 | 说明 |
|---|---|
| 操作系统 | Windows 10 / 11 (64-bit) |
| 运行时 | .NET 8 (已自包含在 exe 中,无需安装) |
| 权限 | 管理员权限(防火墙操作 + WMI 查询需要) |
从 publish/ 目录获取 WindowsNetworkManager.exe(约 44MB),右键 以管理员身份运行。
# Linux(交叉编译为 Windows exe)
./build.sh
# Windows
BuildAndPublish.bat
# 手动
dotnet publish src/WindowsNetworkManager.csproj \
-c Release -r win-x64 --self-contained true \
-p:PublishSingleFile=true -o publish| 层 | 技术 |
|---|---|
| UI | Avalonia UI 11.1 + FluentTheme + 自定义 M3 样式 |
| MVVM | 手动实现 INotifyPropertyChanged + RelayCommand |
| 进程枚举 | WMI Win32_Process + System.Diagnostics.Process |
| 网络监控 | NetworkInterface.GetIPv4Statistics() + GetExtendedTcpTable (IPv4/IPv6) |
| 防火墙 | Windows Firewall COM API (INetFwRule) |
| 图标提取 | System.Drawing.Common Icon.ExtractAssociatedIcon |
| 打包 | dotnet publish Single File + SelfContained |
WindowsNetworkManager/
├── build.sh / BuildAndPublish.bat
├── README.md / DEVLOG.md
├── publish/
│ └── WindowsNetworkManager.exe # 单文件输出
└── src/
├── WindowsNetworkManager.csproj # .NET 8 + Avalonia
├── app.manifest # requireAdministrator
├── Program.cs # 入口
├── App.axaml / .axaml.cs # M3 色彩 Token + 主题切换
├── MainWindow.axaml / .axaml.cs # M3 主界面 + 动画
├── Models/
│ └── Models.cs # AppProcessInfo, NetworkPermission, SortMode
├── Native/
│ ├── IpHelper.cs # IP Helper P/Invoke (TCP/UDP IPv4/IPv6)
│ └── FirewallApi.cs # INetFwRule COM 接口
├── Services/
│ ├── ProcessService.cs # WMI 进程树构建
│ ├── NetworkMonitorService.cs # 网络带宽监控
│ ├── FirewallService.cs # 防火墙规则管理(临时/永久)
│ ├── HostsFileService.cs # Hosts 文件读写
│ └── IconService.cs # exe 图标提取
├── ViewModels/
│ ├── MainViewModel.cs # MVVM 主逻辑
│ └── ProcessNodeViewModel.cs # 单进程 ViewModel
└── Converters/
└── Converters.cs # IValueConverter
| Token | Light | Dark | 用途 |
|---|---|---|---|
M3_Primary |
#6750A4 |
#D0BCFF |
主色调(Filled Button) |
M3_Surface |
#FEF7FF |
#141218 |
列表背景 |
M3_SurfaceLow |
#F7F2FA |
#1D1B20 |
工具栏 / App Bar |
M3_SurfaceContainer |
#F3EDF7 |
#211F26 |
Chip / 搜索框背景 |
M3_OnSurface |
#1C1B1F |
#E6E1E5 |
正文 |
M3_OnSurfaceVariant |
#49454F |
#CAC4D0 |
辅助文字 |
M3_Outline |
#79747E |
#938F99 |
边框 |
| Class | 规格 | 用途 |
|---|---|---|
M3Filled |
H=36, R=20, Primary 填充 | 主题切换按钮 |
M3Tonal |
H=36, R=20, PrimaryContainer 填充 | Hosts 按钮 |
M3Chip |
H=32, R=8, Outline 边框 | 联网控制(🚫♾⬆⬇✅) |
M3Segmented |
H=36, R=20, Outline 边框 | 排序模式 |
M3Icon |
36×36, R=18(正圆) | 标题栏按钮 |
| 权限 | 图标 | 防火墙规则 | 关闭程序后 |
|---|---|---|---|
| 允许全部 | ✅ | 无 | — |
| 临时禁止 | 🚫 | 出站+入站 Block | 自动清理 |
| 永久禁止 | ♾ | 出站+入站 Block(Permanent_ 前缀) |
保留 |
| 仅上传 | ⬆ | 入站 Block | 自动清理 |
| 仅下载 | ⬇ | 出站 Block | 自动清理 |
| 局限 | 说明 |
|---|---|
| 速度是估算值 | 全局带宽按进程连接数比例分配,非精确 per-socket 统计 |
| 需要管理员 | 非管理员运行时防火墙操作静默失败 |
| WMI 依赖 | 某些系统进程可能因权限问题无法获取信息 |
完整记录从 WPF 原型到 Material Design 3 交付的全部开发历程。
一个基于 Avalonia UI + .NET 8 的 Windows 网络管理器,使用 Windows Filtering Platform 和 IP Helper API 实现进程级网络流量监控与联网权限控制。支持 Material Design 3 风格界面、深色/浅色主题切换,可编译为单文件 exe。
目标: 搭建项目骨架,实现核心功能
| 文件 | 说明 |
|---|---|
WindowsNetworkManager.csproj |
.NET 8 WPF 项目,引用 CommunityToolkit.Mvvm + System.Management |
app.manifest |
requireAdministrator — 防火墙操作需要管理员权限 |
Models/Models.cs |
AppProcessInfo(进程树节点)、NetworkPermission(Blocked/UploadOnly/DownloadOnly/AllowAll)、SortMode(四种排行) |
Native/IpHelper.cs |
P/Invoke 封装 IP Helper API:GetExtendedTcpTable、GetExtendedUdpTable、GetPerTcpConnectionEStats、MIB_TCPROW_OWNER_PID 等结构体 |
Native/FirewallApi.cs |
COM 接口定义 INetFwRule,用于操作 Windows 防火墙规则 |
Services/ProcessService.cs |
WMI 查询 Win32_Process 获取进程树(ParentProcessId),构建 flat list 树 |
Services/NetworkMonitorService.cs |
每秒轮询 TCP ESTATS 获取每个连接的收发字节,按 PID 聚合计算速度 |
Services/FirewallService.cs |
动态创建/删除出站/入站防火墙阻止规则,按 NetworkPermission 控制联网 |
ViewModels/MainViewModel.cs |
MVVM 核心:进程刷新、网络统计更新、排序过滤、权限切换命令 |
ViewModels/ProcessNodeViewModel.cs |
单进程 ViewModel:速度/总量文本格式化、展开折叠状态 |
Converters/Converters.cs |
BoolToVisibilityConverter、PermissionToColorConverter、ExpandCollapseConverter 等 |
MainWindow.xaml |
自定义窗口边框、搜索栏、排序按钮、主题切换、TreeView 进程列表、状态栏 |
问题: WPF 无法在 Linux 上编译。
目标: 支持 Linux 编译 + Windows 单文件发布
| 变更 | WPF | Avalonia |
|---|---|---|
| 目标框架 | net8.0-windows |
net8.0 |
| UI 框架 | UseWPF=true |
Avalonia + Avalonia.Desktop |
| 主题 | 手动 ResourceDictionary | FluentTheme |
| 入口 | App.xaml → App.xaml.cs |
Program.cs → App.axaml → App.axaml.cs |
| XAML 命名空间 | http://schemas.microsoft.com/winfx/2006/xaml/presentation |
https://github.com/avaloniaui |
Program.cs: 新增 Avalonia 应用启动入口App.axaml/.axaml.cs:FluentTheme代替自定义主题,RequestedThemeVariant切换暗色/亮色MainWindow.axaml/.axaml.cs: 重写 XAML(Avalonia 语法),自定义窗口边框、列表控件Converters/Converters.cs: 改用Avalonia.Data.Converters.IValueConverter接口ViewModels/MainViewModel.cs:Dispatcher.UIThread.InvokeAsync替代 WPF Dispatcher- 移除 Themes 目录 — FluentTheme 内置暗色/亮色
| 错误 | 原因 | 修复 |
|---|---|---|
61 个 CS0246 类型未找到 |
缺少 <ImplicitUsings>enable</ImplicitUsings> |
添加 ImplicitUsings |
FluentTheme.Mode 不存在 |
Avalonia 11 改用 RequestedThemeVariant |
使用 ThemeVariant.Dark/Light |
PixelPoint 未找到 |
缺少 using Avalonia; |
添加 using |
Action 委托参数不匹配 |
lambda 用了 2 参数但 Action 是 0 参数 | 改为 () => |
Grid.BorderBrush 不存在 |
Avalonia Grid 无此属性 | 用 Border 包裹 Grid |
ListBox.VirtualizationMode 不存在 |
Avalonia API 差异 | 移除该属性 |
GetPerTcpConnectionEStats 需要通过 SetPerTcpConnectionEStats 先启用 TCP 扩展统计(ESTATS)数据收集,否则返回总是 0。
Native/IpHelper.cs:- 新增
TCP_ESTATS_DATA_RW_v0结构体(EnableCollection字段) - 新增
SetPerTcpConnectionEStatsP/Invoke - 新增
EnableTcpEstats()方法:为指定连接启用数据统计
- 新增
Services/NetworkMonitorService.cs:- 新增
_enabledEndpointsHashSet 跟踪已启用的连接 CollectCurrentStats()中首次遇到新连接时调用EnableTcpEstats()
- 新增
原因: ESTATS 在不同 Windows 版本/配置下兼容性差,即使启用也可能失败。
新方案:
- 使用
System.Net.NetworkInformation.NetworkInterface.GetIPv4Statistics()获取全局网络流量 - 比较前后两次 poll 的差值得到每秒全局带宽
- 通过
GetExtendedTcpTable获取各进程的活跃 TCP 连接数 - 按连接数比例将全局带宽分配到各进程
double ratio = (double)procConnections / totalConnections;
long upBps = (long)(globalUploadBps * ratio);
long dnBps = (long)(globalDownloadBps * ratio);优点: 可靠、跨版本兼容、无需启用 ESTATS。
Models/Models.cs: 新增NetworkPermission.PermanentBlocked枚举值Services/FirewallService.cs:- 新增
PermanentPrefix = "WNetMgr_Permanent_" SetProcessPermission(): PermanentBlocked 使用永久前缀创建防火墙规则CleanupAllRules(): 只清理临时规则(WNetMgr_*),跳过永久规则(WNetMgr_Permanent_*)- 新增
CleanupPermanentRules(): 清理所有永久规则
- 新增
ViewModels/MainViewModel.cs: 新增PermanentBlockCommand(♾ 按钮)ViewModels/ProcessNodeViewModel.cs:PermanentBlocked→ "永久禁止" 文本Converters/Converters.cs:PermanentBlocked→ 紫色#6750A4MainWindow.axaml: 新增 ♾ 永久禁止按钮
Services/HostsFileService.cs(新文件):ReadHosts()/WriteHosts(): 读写系统 hosts 文件OpenInExternalEditor(): 用记事本打开 hosts 文件BlockDomain()/UnblockDomain(): 添加/移除127.0.0.1 domain #WNetMgr条目
ViewModels/MainViewModel.cs: 新增OpenHostsEditorCommandMainWindow.axaml: 工具栏新增 📝Hosts 按钮
根因: ApplySortAndFilter() 中 Processes.Clear() + Add() 重建集合,导致 ListBox 选择状态 lost → 随机重映射。
修复: 将 ListBox 替换为 ItemsControl(无选择行为),禁用所有 selection 样式。
根因: 工具栏按钮和权限按钮使用不同的 Width/Height/Padding。
修复: 定义 Button.ActionBtn 样式(28x28 + CornerRadius=8),所有联网控制按钮使用统一样式类。
基于 m3.material.io 规范实现。
定义 13 个 M3 颜色 token,在 App.SetTheme() 中按亮色/暗色分别设置:
| Token | Light | Dark | 用途 |
|---|---|---|---|
M3_Primary |
#6750A4 |
#D0BCFF |
主色调 |
M3_Surface |
#FEF7FF |
#141218 |
背景 |
M3_SurfaceLow |
#F7F2FA |
#1D1B20 |
工具栏/AppBar |
M3_SurfaceHigh |
#ECE6F0 |
#2B2930 |
Hover 态 |
M3_SurfaceContainer |
#F3EDF7 |
#211F26 |
搜索框/Chip 背景 |
M3_OnSurface |
#1C1B1F |
#E6E1E5 |
正文文字 |
M3_OnSurfaceVariant |
#49454F |
#CAC4D0 |
辅助文字 |
M3_Outline |
#79747E |
#938F99 |
边框 |
M3_OutlineVariant |
#CAC4D0 |
#49454F |
分割线 |
M3_Error |
#B3261E |
#F2B8B5 |
错误色 |
| 类 | 规格 | 用途 |
|---|---|---|
M3Filled |
H=36, CornerRadius=20, Primary 背景, OnPrimary 文字 | 主题切换按钮 |
M3Tonal |
H=36, CornerRadius=20, PrimaryContainer 背景 | Hosts 按钮 |
M3Chip |
H=32, CornerRadius=8, Outline 边框 | 联网控制按钮(🚫禁止/♾永久/⬆上传/⬇下载/✅允许) |
M3Segmented |
H=36, CornerRadius=20, Outline 边框 | 排序模式切换 |
M3Icon |
36x36, CornerRadius=18(正圆) | 窗口标题栏按钮 |
窗口 → M3_Surface (CornerRadius=16)
├── Top App Bar → M3_SurfaceLow
├── Toolbar → M3_SurfaceLow
├── Column Headers → M3_SurfaceLow
├── Process List → M3_Surface
└── Bottom Bar → M3_SurfaceLow
- 行高: 48px(单行列表)
- 内边距: 16px(Toolbar/Headers)、12px(Button padding)
- 间距: 8px(组件间距)、12px(大间距)
- 圆角: 8px(Chip)、16px(窗口)、20px(按钮)、28px(搜索框)
根因:
ExtendClientAreaChromeHints="NoChrome"完全禁用了系统级 resize 边框- 标题栏上存在一个透明的
Panel覆盖层捕获PointerPressed,阻挡了下层 Button 的点击事件
修复:
NoChrome→SystemChrome,启用系统绘制的 resize handles- 去掉独立 Panel 层,将
PointerPressed="OnTitleBarPressed"直接放到 Top App Bar 的Border上 - 标题
TextBlock添加IsHitTestVisible="False",避免拦截拖拽手势
根因: M3 按钮样式(M3Filled/M3Tonal/M3Chip/M3Segmented)缺少 VerticalContentAlignment。
修复: 所有 M3 按钮 Style 统一添加 VerticalContentAlignment="Center"。
根因: Chip 按钮带文字标签("🚫 禁止"/"♾ 永久"等)总宽度远超列宽 250px。
修复:
- Chip 按钮改回纯图标(🚫/♾/⬆/⬇/✅),由 ToolTip 说明功能
- 窗口宽度: 1100px → 1200px
- 联网控制列宽: 250px → 380px
根因:
OnNetworkStatsUpdated每秒调用ApplySortAndFilter()→Processes.Clear()+Add()重建整个列表- 排序值变化时,同一进程可能在不同轮次处于不同位置,导致视觉抖动
修复:
| 变更 | 效果 |
|---|---|
从 OnNetworkStatsUpdated 移除 ApplySortAndFilter() 调用 |
每秒 stats 更新仅原地刷新 ViewModel 属性值(INotifyPropertyChanged),不重排列表 |
ApplySortAndFilter() 改用 Move()/Insert()/RemoveAt() |
不再 Clear()→Add(),避免列表瞬间变空导致的闪烁 |
// 旧:全量重建
Processes.Clear();
foreach (var item in sortedList)
Processes.Add(item);
// 新:增量更新
for (int i = Processes.Count - 1; i >= 0; i--)
if (!targetList.Contains(Processes[i]))
Processes.RemoveAt(i);
for (int i = 0; i < targetList.Count; i++)
{
int curIdx = Processes.IndexOf(targetList[i]);
if (curIdx < 0)
Processes.Insert(i, targetList[i]);
else if (curIdx != i)
Processes.Move(curIdx, i);
}WindowsNetworkManager/
├── build.sh # Linux 构建脚本
├── BuildAndPublish.bat # Windows 构建脚本
├── README.md
├── publish/
│ └── WindowsNetworkManager.exe # 单文件输出 (44MB)
└── src/
├── WindowsNetworkManager.csproj
├── app.manifest
├── Program.cs # 入口
├── App.axaml # 应用 XAML + M3 默认资源
├── App.axaml.cs # 主题切换 + M3 Token 管理
├── MainWindow.axaml # Material 3 主界面
├── MainWindow.axaml.cs # 窗口控制(拖动、最大化、关闭)
├── Models/
│ └── Models.cs # AppProcessInfo, NetworkPermission, SortMode
├── Native/
│ ├── IpHelper.cs # IP Helper API P/Invoke(TCP/UDP 连接 + ESTATS)
│ └── FirewallApi.cs # INetFwRule COM 接口
├── Services/
│ ├── ProcessService.cs # WMI 进程树构建
│ ├── NetworkMonitorService.cs# NetworkInterface 全局带宽 + 按比例分配
│ ├── FirewallService.cs # 防火墙规则管理(临时/永久)
│ ├── HostsFileService.cs # Hosts 文件读写/编辑
│ └── IconService.cs # exe 图标提取 + AvaloniaBitmap 转换
├── ViewModels/
│ ├── MainViewModel.cs # MVVM 主逻辑 + RelayCommand
│ └── ProcessNodeViewModel.cs # 单进程 ViewModel
└── Converters/
└── Converters.cs # IValueConverter 实现
# Linux 编译 + 发布 Windows exe
./build.sh
# Windows 上
BuildAndPublish.bat
# 手动
dotnet publish src/WindowsNetworkManager.csproj \
-c Release -r win-x64 --self-contained true \
-p:PublishSingleFile=true -o publish| 局限性 | 说明 |
|---|---|
| 网络速度是估算值 | 全局带宽按连接数比例分配,非精确 per-socket 统计 |
| 防火墙规则需要管理员 | 非管理员运行时防火墙操作静默失败 |
| WMI 进程枚举 | 某些系统进程可能因权限问题无法获取信息 |
根因: 只枚举 IPv4 TCP 连接,现代 Windows 大部分流量走 IPv6。当 pidConns 为空时,无任何进程能分配到全局带宽。
修复 (Services/NetworkMonitorService.cs, Native/IpHelper.cs):
| 变更 | 说明 |
|---|---|
新增 GetAllTcp6Connections() |
枚举 IPv6 TCP 连接(AF_INET6),转换为统一的 MIB_TCPROW_OWNER_PID |
| 合并 IPv4 + IPv6 + UDP | CollectStats() 同时统计三种协议的连接数 |
| Fallback 机制 | P/Invoke 全部失败时,降级用 IPGlobalProperties.GetActiveTcpConnections() 获取连接数,按所有运行中进程均匀分配 |
根因: 列内文本 HorizontalAlignment="Center",不同数字宽度不一致("0 B/s" vs "123.4 KB/s")导致列间不对齐。
修复: 上传速度、下载速度、上传总量、下载总量四列改为 HorizontalAlignment="Right" + Margin="0,0,12,0",表头同步右对齐。
实现 (Services/IconService.cs):
- 新增
System.Drawing.Common依赖 Icon.ExtractAssociatedIcon(path)→Bitmap→MemoryStream(PNG)→AvaloniaBitmapConcurrentDictionary缓存已提取图标,Null 时降级为权限色圆圈ProcessNodeViewModel.Icon绑定到 XAML<Image Source="{Binding Icon}"/>
实现 (MainWindow.axaml + .axaml.cs):
- 窗口顶层添加
ThemeOverlayBorder(IsHitTestVisible="False", ZIndex=999) - 切换时 Opacity 0→0.2 (120ms) → 0.0 (180ms),
CancellationTokenSource防止重复动画 - 覆盖层
Background="{DynamicResource M3_OnSurface}"产生短暂暗/亮闪烁感
| 问题 | 修复 |
|---|---|
| 子进程默认展开 | ProcessService 中 IsExpanded 默认值 true → false |
| 展开按钮不生效 | 新增 SetProcessExpanded(pid, expanded) 方法,ToggleExpand 时同步更新 _processCache |
| 按钮位置偏左上 | DockPanel → StackPanel Orientation="Horizontal",按钮显式设 HorizontalContentAlignment="Center" + VerticalContentAlignment="Center" |
根因: DockPanel 在 Avalonia 中子元素布局异常,TextBox 被压缩到左上角。
修复: 改为 Grid 三列(🔍 | TextBox | ✕),Border 显式设 Height="40" 对齐工具栏行高。
修复: M3Filled/M3Tonal 按钮 ContentPresenter 添加 DoubleTransition(Opacity, 0.12s) 平滑过渡。
最后更新: 2026-07-31 (Phase 8)