基于C# WinForms开发的Windows系统监控工具
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>前言</li><li>技术栈</li><li>核心功能</li><li>一、硬件监控实现</li><ul class="second_class_ul"><li>1.1 系统监控服务设计</li><li>1.2 性能计数器初始化</li><li>1.3 网络流量监控</li><li>1.4 温度和频率监控</li><li>1.5 电池状态监控(Win11 兼容)</li></ul><li>二、历史数据管理</li><ul class="second_class_ul"></ul><li>三、ScottPlot 图表绘制</li><ul class="second_class_ul"><li>3.1 图表初始化</li><li>3.2 单线图表更新</li><li>3.3 双线图表(温度/网络)</li></ul><li>四、任务栏悬浮窗口</li><ul class="second_class_ul"><li>4.1 窗口基本设置</li><li>4.2 三种显示模式</li><li>4.3 窗口拖拽功能</li><li>4.4 右键菜单切换模式</li></ul><li>五、配置持久化</li><ul class="second_class_ul"><li>5.1 配置数据结构</li><li>5.2 JSON 序列化存储</li></ul><li>六、开机自启动</li><ul class="second_class_ul"><li>6.1 注册表方式实现</li></ul><li>七、UI 布局优化</li><ul class="second_class_ul"><li>7.1 避免控件重叠</li><li>7.2 响应式布局</li></ul><li>八、系统托盘功能</li><ul class="second_class_ul"><li>8.1 托盘图标和菜单</li><li>8.2 窗口最小化到托盘</li></ul><li>总结</li><ul class="second_class_ul"></ul><li>运行截图</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>前言</h2><p>最近开发了一个轻量级的 Windows 系统监控工具,可以实时监控 CPU、内存、GPU、温度、网络流量等硬件信息,并通过曲线图表直观展示。整个项目基于 .NET 10.0 和 WinForms 框架,使用了 LibreHardwareMonitor 硬件监控库和 ScottPlot 图表库。</p>
<p>本文分享一下开发过程中的核心技术点和关键代码实现。</p>
<p class="maodian"></p><h2>技术栈</h2>
<ul><li><strong>.NET 10.0</strong> - 最新的 .NET 平台</li><li><strong>Windows Forms</strong> - 桌面 UI 框架</li><li><strong>LibreHardwareMonitor 0.9.3</strong> - 硬件传感器数据采集</li><li><strong>ScottPlot 5.0</strong> - 高性能实时图表绘制</li><li><strong>PerformanceCounter</strong> - Windows 性能计数器</li></ul>
<p class="maodian"></p><h2>核心功能</h2>
<ol><li>实时监控 CPU 使用率、主频、温度</li><li>内存使用情况监控</li><li>GPU 使用率和温度监控</li><li>网络上传/下载速度统计</li><li>磁盘 I/O 读写速度</li><li>电池电量和充电状态(笔记本)</li><li>历史数据曲线图表展示</li><li>任务栏悬浮小窗口(支持三种显示模式)</li><li>配置持久化存储</li></ol>
<p class="maodian"></p><h2>一、硬件监控实现</h2>
<p class="maodian"></p><h3>1.1 系统监控服务设计</h3>
<p>系统监控服务是整个工具的核心,负责采集各类硬件数据。主要使用两种方式:</p>
<ul><li><strong>PerformanceCounter</strong>:采集 CPU 使用率、内存使用率、网络流量等</li><li><strong>LibreHardwareMonitor</strong>:采集温度、频率、GPU 等硬件传感器数据</li></ul>
<p>核心数据结构:</p>
<div class="jb51code"><pre class="brush:csharp;">public class MonitorData
{
// CPU信息
public float CpuUsage { get; set; }
public float CpuFrequency { get; set; }// CPU当前主频 (MHz)
public float CpuTemperature { get; set; }
public int CpuCoreCount { get; set; }
public int CpuThreadCount { get; set; }
public string CpuName { get; set; } = string.Empty;
// 内存信息
public float MemoryUsage { get; set; }
public long TotalMemoryMB { get; set; }
public long UsedMemoryMB { get; set; }
public long AvailableMemoryMB { get; set; }
// GPU信息
public float GpuTemperature { get; set; }
public float GpuUsage { get; set; }
public string GpuName { get; set; } = string.Empty;
// 网络信息
public float NetworkUploadSpeed { get; set; } // KB/s
public float NetworkDownloadSpeed { get; set; }// KB/s
// 磁盘信息
public float DiskUsage { get; set; }
public long DiskReadSpeed { get; set; }
public long DiskWriteSpeed { get; set; }
// 电池信息
public int BatteryLevel { get; set; }
public bool IsCharging { get; set; }
}
</pre></div>
<p class="maodian"></p><h3>1.2 性能计数器初始化</h3>
<div class="jb51code"><pre class="brush:csharp;">public class SystemMonitor : IDisposable
{
private readonly Computer _computer;
private readonly PerformanceCounter _cpuCounter;
private readonly PerformanceCounter _ramCounter;
private PerformanceCounter? _networkSentCounter;
private PerformanceCounter? _networkReceivedCounter;
public SystemMonitor()
{
// 初始化性能计数器
_cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
_ramCounter = new PerformanceCounter("Memory", "% Committed Bytes In Use");
// 初始化网络计数器
InitializeNetworkCounters();
// 初始化 LibreHardwareMonitor
_computer = new Computer
{
IsCpuEnabled = true,
IsGpuEnabled = true,
IsMemoryEnabled = true,
IsBatteryEnabled = true,
IsNetworkEnabled = true,
IsStorageEnabled = true
};
_computer.Open();
}
}
</pre></div>
<p class="maodian"></p><h3>1.3 网络流量监控</h3>
<p>网络流量监控需要注意的是 PerformanceCounter 返回的是累计值,需要计算两次采样之间的差值来得到速度:</p>
<div class="jb51code"><pre class="brush:csharp;">private void InitializeNetworkCounters()
{
try
{
var category = new PerformanceCounterCategory("Network Interface");
var instanceNames = category.GetInstanceNames();
if (instanceNames.Length > 0)
{
string networkInterface = instanceNames;
_networkSentCounter = new PerformanceCounter(
"Network Interface", "Bytes Sent/sec", networkInterface);
_networkReceivedCounter = new PerformanceCounter(
"Network Interface", "Bytes Received/sec", networkInterface);
}
}
catch { }
}
private void UpdateNetworkData(MonitorData data)
{
try
{
if (_networkSentCounter != null && _networkReceivedCounter != null)
{
long bytesSent = (long)_networkSentCounter.NextValue();
long bytesReceived = (long)_networkReceivedCounter.NextValue();
var now = DateTime.Now;
var timeDiff = (now - _lastNetworkUpdate).TotalSeconds;
if (timeDiff > 0 && _lastBytesSent > 0)
{
// 计算速度 (KB/s)
data.NetworkUploadSpeed =
(float)((bytesSent - _lastBytesSent) / timeDiff / 1024);
data.NetworkDownloadSpeed =
(float)((bytesReceived - _lastBytesReceived) / timeDiff / 1024);
}
_lastBytesSent = bytesSent;
_lastBytesReceived = bytesReceived;
_lastNetworkUpdate = now;
}
}
catch { }
}
</pre></div>
<p class="maodian"></p><h3>1.4 温度和频率监控</h3>
<p>使用 LibreHardwareMonitor 获取 CPU/GPU 温度和频率信息:</p>
<div class="jb51code"><pre class="brush:csharp;">private void UpdateData()
{
var data = new MonitorData();
// 获取 CPU 使用率
data.CpuUsage = _cpuCounter.NextValue();
// 更新硬件传感器信息
foreach (var hardware in _computer.Hardware)
{
hardware.Update();
// CPU 温度和频率
if (hardware.HardwareType == HardwareType.Cpu)
{
foreach (var sensor in hardware.Sensors)
{
if (sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue)
{
data.CpuTemperature = Math.Max(data.CpuTemperature, sensor.Value.Value);
}
// 获取 CPU 主频
if (sensor.SensorType == SensorType.Clock &&
sensor.Name.Contains("Core") && sensor.Value.HasValue)
{
data.CpuFrequency = Math.Max(data.CpuFrequency, sensor.Value.Value);
}
}
}
// GPU 温度和使用率
if (hardware.HardwareType == HardwareType.GpuNvidia ||
hardware.HardwareType == HardwareType.GpuAmd ||
hardware.HardwareType == HardwareType.GpuIntel)
{
foreach (var sensor in hardware.Sensors)
{
if (sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue)
{
data.GpuTemperature = Math.Max(data.GpuTemperature, sensor.Value.Value);
}
if (sensor.SensorType == SensorType.Load &&
sensor.Name.Contains("Core") && sensor.Value.HasValue)
{
data.GpuUsage = Math.Max(data.GpuUsage, sensor.Value.Value);
}
}
}
}
DataUpdated?.Invoke(this, data);
}
</pre></div>
<p class="maodian"></p><h3>1.5 电池状态监控(Win11 兼容)</h3>
<p>电池状态监控在 Win11 上需要特别处理,使用 SystemInformation.PowerStatus API:</p>
<div class="jb51code"><pre class="brush:csharp;">try
{
var status = System.Windows.Forms.SystemInformation.PowerStatus;
// 检查是否有电池
if (status.BatteryLifePercent >= 0 && status.BatteryLifePercent <= 1 &&
status.BatteryChargeStatus != System.Windows.Forms.BatteryChargeStatus.NoSystemBattery)
{
// 电池百分比
data.BatteryLevel = (int)(status.BatteryLifePercent * 100);
// 充电状态
data.IsCharging = status.PowerLineStatus == System.Windows.Forms.PowerLineStatus.Online ||
status.BatteryChargeStatus.HasFlag(System.Windows.Forms.BatteryChargeStatus.Charging);
}
else
{
// 台式机或没有电池的设备
data.BatteryLevel = -1;// 用 -1 表示无电池
data.IsCharging = false;
}
}
catch
{
data.BatteryLevel = -1;
data.IsCharging = false;
}
</pre></div>
<p class="maodian"></p><h2>二、历史数据管理</h2>
<p>为了绘制历史曲线,需要维护一个固定大小的数据队列:</p>
<div class="jb51code"><pre class="brush:csharp;">public class DataHistory
{
private readonly int _maxDataPoints;
private readonly Queue<float> _cpuHistory;
private readonly Queue<float> _memoryHistory;
private readonly Queue<float> _cpuTempHistory;
private readonly Queue<float> _gpuTempHistory;
// ... 其他数据队列
public DataHistory(int maxDataPoints = 60)
{
_maxDataPoints = maxDataPoints;
_cpuHistory = new Queue<float>(maxDataPoints);
_memoryHistory = new Queue<float>(maxDataPoints);
// 初始化其他队列...
}
public void AddData(MonitorData data)
{
AddToQueue(_cpuHistory, data.CpuUsage);
AddToQueue(_memoryHistory, data.MemoryUsage);
AddToQueue(_cpuTempHistory, data.CpuTemperature);
// 添加其他数据...
}
private void AddToQueue(Queue<float> queue, float value)
{
if (queue.Count >= _maxDataPoints)
{
queue.Dequeue();
}
queue.Enqueue(value);
}
public double[] GetCpuHistory() => _cpuHistory.Select(x => (double)x).ToArray();
public double[] GetMemoryHistory() => _memoryHistory.Select(x => (double)x).ToArray();
// 其他获取方法...
}
</pre></div>
<p class="maodian"></p><h2>三、ScottPlot 图表绘制</h2>
<p class="maodian"></p><h3>3.1 图表初始化</h3>
<p>ScottPlot 5.0 提供了强大的实时图表绘制能力:</p>
<div class="jb51code"><pre class="brush:csharp;">private void SetupPlot(FormsPlot plot, string title, Color lineColor, double yMin = 0, double yMax = 100)
{
plot.Plot.Title(title);
plot.Plot.Axes.Title.Label.ForeColor = ScottColor.FromColor(Color.White);
plot.Plot.FigureBackground.Color = ScottColor.FromColor(Color.FromArgb(40, 40, 40));
plot.Plot.DataBackground.Color = ScottColor.FromColor(Color.FromArgb(30, 30, 30));
plot.Plot.Axes.Color(ScottColor.FromColor(Color.Gray));
plot.Plot.Grid.MajorLineColor = ScottColor.FromColor(Color.FromArgb(60, 60, 60));
// 设置 Y 轴范围
plot.Plot.Axes.SetLimitsY(yMin, yMax);
}
</pre></div>
<p class="maodian"></p><h3>3.2 单线图表更新</h3>
<div class="jb51code"><pre class="brush:csharp;">private void UpdatePlot(FormsPlot? plot, double[] data, Color lineColor)
{
if (plot == null || data.Length == 0) return;
plot.Plot.Clear();
var signal = plot.Plot.Add.Signal(data);
signal.Color = ScottColor.FromColor(lineColor);
signal.LineWidth = 2;
plot.Plot.Axes.SetLimitsX(0, data.Length);
plot.Plot.Axes.SetLimitsY(0, 100);
plot.Refresh();
}
</pre></div>
<p class="maodian"></p><h3>3.3 双线图表(温度/网络)</h3>
<p>温度图表同时显示 CPU 和 GPU 温度,网络图表同时显示上传和下载速度:</p>
<div class="jb51code"><pre class="brush:csharp;">private void UpdateDualLinePlot(FormsPlot? plot, double[] data1, double[] data2,
string legend1, string legend2, Color color1, Color color2)
{
if (plot == null) return;
plot.Plot.Clear();
if (data1.Length > 0)
{
var signal1 = plot.Plot.Add.Signal(data1);
signal1.Color = ScottColor.FromColor(color1);
signal1.LineWidth = 2;
signal1.LegendText = legend1;
}
if (data2.Length > 0)
{
var signal2 = plot.Plot.Add.Signal(data2);
signal2.Color = ScottColor.FromColor(color2);
signal2.LineWidth = 2;
signal2.LegendText = legend2;
}
plot.Plot.ShowLegend();
plot.Plot.Axes.SetLimitsX(0, Math.Max(data1.Length, data2.Length));
// 自动调整 Y 轴范围
if (data1.Length > 0 || data2.Length > 0)
{
double maxValue = 0;
if (data1.Length > 0) maxValue = Math.Max(maxValue, data1.Max());
if (data2.Length > 0) maxValue = Math.Max(maxValue, data2.Max());
plot.Plot.Axes.SetLimitsY(0, Math.Max(10, maxValue * 1.2));
}
plot.Refresh();
}
</pre></div>
<p class="maodian"></p><h2>四、任务栏悬浮窗口</h2>
<p class="maodian"></p><h3>4.1 窗口基本设置</h3>
<p>任务栏小窗口使用无边框窗体,置顶显示,不在任务栏显示:</p>
<div class="jb51code"><pre class="brush:csharp;">private void InitializeComponent()
{
this.SuspendLayout();
this.AutoScaleDimensions = new SizeF(7F, 17F);
this.AutoScaleMode = AutoScaleMode.Font;
this.ClientSize = new Size(400, 135);
this.FormBorderStyle = FormBorderStyle.None;
this.Name = "TaskbarWindow";
this.TopMost = true;
this.ShowInTaskbar = false;
this.StartPosition = FormStartPosition.Manual;
this.BackColor = Color.FromArgb(30, 30, 30);
this.ResumeLayout(false);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x80; // WS_EX_TOOLWINDOW - 不显示在 Alt+Tab 中
return cp;
}
}
</pre></div>
<p class="maodian"></p><h3>4.2 三种显示模式</h3>
<p>小窗口支持三种显示模式,通过右键菜单切换:</p>
<p><strong>模式 0:CPU + 内存图表</strong></p>
<div class="jb51code"><pre class="brush:csharp;">private void SetupMode0_CpuMemory()
{
_cpuPlot = new FormsPlot
{
Location = new Point(5, 30),
Size = new Size(190, 100),
BackColor = Color.FromArgb(40, 40, 40)
};
SetupPlot(_cpuPlot, "CPU", Color.FromArgb(0, 174, 219));
this.Controls.Add(_cpuPlot);
_memoryPlot = new FormsPlot
{
Location = new Point(205, 30),
Size = new Size(190, 100),
BackColor = Color.FromArgb(40, 40, 40)
};
SetupPlot(_memoryPlot, "内存", Color.FromArgb(142, 68, 173));
this.Controls.Add(_memoryPlot);
}
</pre></div>
<p><strong>模式 1:温度 + 网络图表</strong></p>
<div class="jb51code"><pre class="brush:csharp;">private void SetupMode1_TempNetwork()
{
_tempPlot = new FormsPlot
{
Location = new Point(5, 30),
Size = new Size(190, 100),
BackColor = Color.FromArgb(40, 40, 40)
};
SetupPlot(_tempPlot, "温度", Color.FromArgb(231, 76, 60));
this.Controls.Add(_tempPlot);
_networkPlot = new FormsPlot
{
Location = new Point(205, 30),
Size = new Size(190, 100),
BackColor = Color.FromArgb(40, 40, 40)
};
SetupPlot(_networkPlot, "网络", Color.FromArgb(52, 152, 219));
this.Controls.Add(_networkPlot);
}
</pre></div>
<p><strong>模式 2:详细信息列表</strong></p>
<div class="jb51code"><pre class="brush:csharp;">private void SetupMode2_DetailedInfo()
{
int yPos = 30;
int labelHeight = 13;
var labels = new[]
{
("CPU使用率", "0%"),
("CPU频率", "0 MHz"),
("CPU温度", "0°C"),
("GPU使用率", "0%"),
("GPU温度", "0°C"),
("内存使用率", "0%"),
("网络上传", "0 KB/s"),
("网络下载", "0 KB/s")
};
foreach (var (name, value) in labels)
{
var nameLabel = new Label
{
Text = name + ":",
Location = new Point(10, yPos),
Size = new Size(100, labelHeight),
ForeColor = Color.FromArgb(200, 200, 200),
Font = new Font("Microsoft YaHei UI", 8F),
TextAlign = ContentAlignment.MiddleLeft
};
this.Controls.Add(nameLabel);
var valueLabel = new Label
{
Text = value,
Location = new Point(120, yPos),
Size = new Size(270, labelHeight),
ForeColor = Color.White,
Font = new Font("Microsoft YaHei UI", 8F, FontStyle.Bold),
TextAlign = ContentAlignment.MiddleLeft,
Tag = name // 用于在更新时识别标签
};
this.Controls.Add(valueLabel);
yPos += labelHeight;
}
}
</pre></div>
<p class="maodian"></p><h3>4.3 窗口拖拽功能</h3>
<p>实现窗口拖拽移动:</p>
<div class="jb51code"><pre class="brush:csharp;">private Point _dragStartPoint;
private bool _isDragging = false;
private void TaskbarWindow_MouseDown(object? sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_isDragging = true;
_dragStartPoint = e.Location;
}
}
private void TaskbarWindow_MouseMove(object? sender, MouseEventArgs e)
{
if (_isDragging)
{
Point newLocation = this.Location;
newLocation.X += e.X - _dragStartPoint.X;
newLocation.Y += e.Y - _dragStartPoint.Y;
this.Location = newLocation;
}
if (e.Button == MouseButtons.None)
{
_isDragging = false;
}
}
</pre></div>
<p class="maodian"></p><h3>4.4 右键菜单切换模式</h3>
<div class="jb51code"><pre class="brush:csharp;">private void SetupContextMenu()
{
var contextMenu = new ContextMenuStrip();
var modeMenu = new ToolStripMenuItem("切换显示模式");
var mode0 = new ToolStripMenuItem("CPU + 内存图表")
{
Checked = _displayMode == 0
};
mode0.Click += (s, e) => SwitchDisplayMode(0);
var mode1 = new ToolStripMenuItem("温度 + 网络图表")
{
Checked = _displayMode == 1
};
mode1.Click += (s, e) => SwitchDisplayMode(1);
var mode2 = new ToolStripMenuItem("详细信息列表")
{
Checked = _displayMode == 2
};
mode2.Click += (s, e) => SwitchDisplayMode(2);
modeMenu.DropDownItems.Add(mode0);
modeMenu.DropDownItems.Add(mode1);
modeMenu.DropDownItems.Add(mode2);
contextMenu.Items.Add(modeMenu);
contextMenu.Items.Add(new ToolStripSeparator());
contextMenu.Items.Add("关闭", null, (s, e) => this.Close());
this.ContextMenuStrip = contextMenu;
}
private void SwitchDisplayMode(int mode)
{
_displayMode = mode;
_settings.TaskbarWindowDisplayMode = mode;
// 保存配置
Utils.SettingsManager.Save(_settings);
// 重新创建界面
SetupWindow();
}
</pre></div>
<p class="maodian"></p><h2>五、配置持久化</h2>
<p class="maodian"></p><h3>5.1 配置数据结构</h3>
<div class="jb51code"><pre class="brush:csharp;">public class AppSettings
{
public bool AutoStart { get; set; } = false;
public int RefreshInterval { get; set; } = 1000;
public bool ShowTaskbarWindow { get; set; } = true;
public int TaskbarWindowX { get; set; } = -1;
public int TaskbarWindowY { get; set; } = -1;
public int HistoryDuration { get; set; } = 120;
public bool StartMinimized { get; set; } = false;
public bool EnableTemperatureMonitoring { get; set; } = true;
public int MainWindowWidth { get; set; } = 900;
public int MainWindowHeight { get; set; } = 600;
public int TaskbarWindowDisplayMode { get; set; } = 0;
}
</pre></div>
<p class="maodian"></p><h3>5.2 JSON 序列化存储</h3>
<div class="jb51code"><pre class="brush:csharp;">public static class SettingsManager
{
private static readonly string SettingsPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"WindowsMonitor",
"settings.json"
);
public static AppSettings Load()
{
try
{
if (File.Exists(SettingsPath))
{
string json = File.ReadAllText(SettingsPath);
return JsonSerializer.Deserialize<AppSettings>(json) ?? new AppSettings();
}
}
catch { }
return new AppSettings();
}
public static void Save(AppSettings settings)
{
try
{
string directory = Path.GetDirectoryName(SettingsPath)!;
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
var options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(settings, options);
File.WriteAllText(SettingsPath, json);
}
catch { }
}
public static string GetSettingsPath() => SettingsPath;
}
</pre></div>
<p class="maodian"></p><h2>六、开机自启动</h2>
<p class="maodian"></p><h3>6.1 注册表方式实现</h3>
<div class="jb51code"><pre class="brush:csharp;">public static class AutoStartManager
{
private const string RegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
private const string AppName = "WindowsMonitor";
public static void SetAutoStart(bool enable)
{
try
{
using var key = Registry.CurrentUser.OpenSubKey(RegistryKey, true);
if (key == null) return;
if (enable)
{
string exePath = Application.ExecutablePath;
key.SetValue(AppName, $"\"{exePath}\"");
}
else
{
key.DeleteValue(AppName, false);
}
}
catch { }
}
public static bool IsAutoStartEnabled()
{
try
{
using var key = Registry.CurrentUser.OpenSubKey(RegistryKey, false);
return key?.GetValue(AppName) != null;
}
catch
{
return false;
}
}
}
</pre></div>
<p class="maodian"></p><h2>七、UI 布局优化</h2>
<p class="maodian"></p><h3>7.1 避免控件重叠</h3>
<p>在 WinForms 中,控件重叠是常见问题。需要精确计算每个控件的位置和大小:</p>
<div class="jb51code"><pre class="brush:csharp;">// 使用固定列位置和行位置
int col1X = 15, col2X = 250, col3X = 485, col4X = 720;
int row1Y = 10, row2Y = 40, row3Y = 70, row4Y = 100;
// 创建信息标签时使用固定大小
private Label CreateInfoLabel(string text, Point location, Panel parent)
{
var label = new Label
{
Text = text,
Location = location,
Size = new Size(210, 25),// 固定宽度避免显示不全
AutoSize = false,
Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular),
AutoEllipsis = true// 文字太长时显示省略号
};
parent.Controls.Add(label);
return label;
}
</pre></div>
<p class="maodian"></p><h3>7.2 响应式布局</h3>
<p>使用 Anchor 属性实现窗口大小改变时控件自适应:</p>
<div class="jb51code"><pre class="brush:csharp;">var dataPanel = new Panel
{
Location = new Point(10, 10),
Size = new Size(this.ClientSize.Width - 40, 140),
BackColor = Color.White,
BorderStyle = BorderStyle.FixedSingle,
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
};
</pre></div>
<p class="maodian"></p><h2>八、系统托盘功能</h2>
<p class="maodian"></p><h3>8.1 托盘图标和菜单</h3>
<div class="jb51code"><pre class="brush:csharp;">private void SetupNotifyIcon()
{
_notifyIcon = new NotifyIcon
{
Icon = SystemIcons.Application,
Visible = true,
Text = "Windows 系统监控"
};
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("显示主窗口", null, (s, e) => ShowMainWindow());
contextMenu.Items.Add("任务栏窗口", null, (s, e) => ToggleTaskbarWindow());
contextMenu.Items.Add(new ToolStripSeparator());
contextMenu.Items.Add("退出", null, (s, e) => Application.Exit());
_notifyIcon.ContextMenuStrip = contextMenu;
_notifyIcon.DoubleClick += (s, e) => ShowMainWindow();
}
</pre></div>
<p class="maodian"></p><h3>8.2 窗口最小化到托盘</h3>
<div class="jb51code"><pre class="brush:csharp;">private void MainWindow_Resize(object? sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
this.Hide();
}
}
private void MainWindow_FormClosing(object? sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.WindowState = FormWindowState.Minimized;
this.Hide();
}
}
</pre></div>
<p class="maodian"></p><h2>总结</h2>
<p>这个系统监控工具的开发涉及了以下几个关键技术点:</p>
<ol><li><strong>硬件数据采集</strong>:结合 PerformanceCounter 和 LibreHardwareMonitor 实现全面的硬件监控</li><li><strong>数据可视化</strong>:使用 ScottPlot 实现高性能的实时曲线绘制</li><li><strong>UI 设计</strong>:WinForms 布局优化,避免控件重叠</li><li><strong>数据管理</strong>:使用队列管理历史数据,控制内存占用</li><li><strong>配置持久化</strong>:JSON 序列化存储用户配置</li><li><strong>系统集成</strong>:托盘图标、开机自启、悬浮窗口等系统功能</li></ol>
<p>整个项目代码结构清晰,模块化设计良好,后续可以方便地扩展更多监控项和功能。</p>
<p class="maodian"></p><h2>运行截图</h2>
<p>主窗口展示了多个实时曲线图表,任务栏小窗口可以自由拖拽并切换显示模式,整体界面简洁美观,性能开销低。</p>
<p><strong>开发环境要求</strong>:</p>
<ul><li>Visual Studio 2022 或更高版本</li><li>.NET 10.0 SDK</li><li>Windows 10/11 操作系统</li></ul>
<p><strong>依赖包</strong>:</p>
<div class="jb51code"><pre class="brush:xml;"><PackageReference Include="LibreHardwareMonitorLib" Version="0.9.3" />
<PackageReference Include="ScottPlot.WinForms" Version="5.0.47" />
</pre></div>
<p>以上就是基于C# WinForms开发的Windows系统监控工具的详细内容,更多关于C# WinForms Windows系统监控的资料请关注琼殿技术社区其它相关文章!</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>C# WinForms程序调用Python脚本的完整代码案例</li><li>使用C#和WinForms创建动态图表的两种方法</li><li>C# WinForms使用CyUSB.dll访问USB设备的实现步骤</li><li>C# WinForms存储过程操作数据库的实例讲解</li><li>C# WinForms中实现MD5的加密</li><li>C# WinForms控件拖动实现技巧</li></ul>
</div>
</div>
<!--endmain-->
頁:
[1]