基于C# WinForms開發(fā)的Windows系統(tǒng)監(jiān)控工具
前言
最近開發(fā)了一個輕量級的 Windows 系統(tǒng)監(jiān)控工具,可以實時監(jiān)控 CPU、內(nèi)存、GPU、溫度、網(wǎng)絡(luò)流量等硬件信息,并通過曲線圖表直觀展示。整個項目基于 .NET 10.0 和 WinForms 框架,使用了 LibreHardwareMonitor 硬件監(jiān)控庫和 ScottPlot 圖表庫。
本文分享一下開發(fā)過程中的核心技術(shù)點和關(guān)鍵代碼實現(xiàn)。
技術(shù)棧
- .NET 10.0 - 最新的 .NET 平臺
- Windows Forms - 桌面 UI 框架
- LibreHardwareMonitor 0.9.3 - 硬件傳感器數(shù)據(jù)采集
- ScottPlot 5.0 - 高性能實時圖表繪制
- PerformanceCounter - Windows 性能計數(shù)器
核心功能
- 實時監(jiān)控 CPU 使用率、主頻、溫度
- 內(nèi)存使用情況監(jiān)控
- GPU 使用率和溫度監(jiān)控
- 網(wǎng)絡(luò)上傳/下載速度統(tǒng)計
- 磁盤 I/O 讀寫速度
- 電池電量和充電狀態(tài)(筆記本)
- 歷史數(shù)據(jù)曲線圖表展示
- 任務(wù)欄懸浮小窗口(支持三種顯示模式)
- 配置持久化存儲
一、硬件監(jiān)控實現(xiàn)
1.1 系統(tǒng)監(jiān)控服務(wù)設(shè)計
系統(tǒng)監(jiān)控服務(wù)是整個工具的核心,負(fù)責(zé)采集各類硬件數(shù)據(jù)。主要使用兩種方式:
- PerformanceCounter:采集 CPU 使用率、內(nèi)存使用率、網(wǎng)絡(luò)流量等
- LibreHardwareMonitor:采集溫度、頻率、GPU 等硬件傳感器數(shù)據(jù)
核心數(shù)據(jù)結(jié)構(gòu):
public class MonitorData
{
// CPU信息
public float CpuUsage { get; set; }
public float CpuFrequency { get; set; } // CPU當(dāng)前主頻 (MHz)
public float CpuTemperature { get; set; }
public int CpuCoreCount { get; set; }
public int CpuThreadCount { get; set; }
public string CpuName { get; set; } = string.Empty;
// 內(nèi)存信息
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;
// 網(wǎng)絡(luò)信息
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; }
}
1.2 性能計數(shù)器初始化
public class SystemMonitor : IDisposable
{
private readonly Computer _computer;
private readonly PerformanceCounter _cpuCounter;
private readonly PerformanceCounter _ramCounter;
private PerformanceCounter? _networkSentCounter;
private PerformanceCounter? _networkReceivedCounter;
public SystemMonitor()
{
// 初始化性能計數(shù)器
_cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
_ramCounter = new PerformanceCounter("Memory", "% Committed Bytes In Use");
// 初始化網(wǎng)絡(luò)計數(shù)器
InitializeNetworkCounters();
// 初始化 LibreHardwareMonitor
_computer = new Computer
{
IsCpuEnabled = true,
IsGpuEnabled = true,
IsMemoryEnabled = true,
IsBatteryEnabled = true,
IsNetworkEnabled = true,
IsStorageEnabled = true
};
_computer.Open();
}
}
1.3 網(wǎng)絡(luò)流量監(jiān)控
網(wǎng)絡(luò)流量監(jiān)控需要注意的是 PerformanceCounter 返回的是累計值,需要計算兩次采樣之間的差值來得到速度:
private void InitializeNetworkCounters()
{
try
{
var category = new PerformanceCounterCategory("Network Interface");
var instanceNames = category.GetInstanceNames();
if (instanceNames.Length > 0)
{
string networkInterface = instanceNames[0];
_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 { }
}
1.4 溫度和頻率監(jiān)控
使用 LibreHardwareMonitor 獲取 CPU/GPU 溫度和頻率信息:
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);
}
1.5 電池狀態(tài)監(jiān)控(Win11 兼容)
電池狀態(tài)監(jiān)控在 Win11 上需要特別處理,使用 SystemInformation.PowerStatus API:
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);
// 充電狀態(tài)
data.IsCharging = status.PowerLineStatus == System.Windows.Forms.PowerLineStatus.Online ||
status.BatteryChargeStatus.HasFlag(System.Windows.Forms.BatteryChargeStatus.Charging);
}
else
{
// 臺式機或沒有電池的設(shè)備
data.BatteryLevel = -1; // 用 -1 表示無電池
data.IsCharging = false;
}
}
catch
{
data.BatteryLevel = -1;
data.IsCharging = false;
}
二、歷史數(shù)據(jù)管理
為了繪制歷史曲線,需要維護(hù)一個固定大小的數(shù)據(jù)隊列:
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;
// ... 其他數(shù)據(jù)隊列
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);
// 添加其他數(shù)據(jù)...
}
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();
// 其他獲取方法...
}
三、ScottPlot 圖表繪制
3.1 圖表初始化
ScottPlot 5.0 提供了強大的實時圖表繪制能力:
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));
// 設(shè)置 Y 軸范圍
plot.Plot.Axes.SetLimitsY(yMin, yMax);
}
3.2 單線圖表更新
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();
}
3.3 雙線圖表(溫度/網(wǎng)絡(luò))
溫度圖表同時顯示 CPU 和 GPU 溫度,網(wǎng)絡(luò)圖表同時顯示上傳和下載速度:
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));
// 自動調(diào)整 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();
}
四、任務(wù)欄懸浮窗口
4.1 窗口基本設(shè)置
任務(wù)欄小窗口使用無邊框窗體,置頂顯示,不在任務(wù)欄顯示:
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;
}
}
4.2 三種顯示模式
小窗口支持三種顯示模式,通過右鍵菜單切換:
模式 0:CPU + 內(nèi)存圖表
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, "內(nèi)存", Color.FromArgb(142, 68, 173));
this.Controls.Add(_memoryPlot);
}
模式 1:溫度 + 網(wǎng)絡(luò)圖表
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, "網(wǎng)絡(luò)", Color.FromArgb(52, 152, 219));
this.Controls.Add(_networkPlot);
}
模式 2:詳細(xì)信息列表
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"),
("內(nèi)存使用率", "0%"),
("網(wǎng)絡(luò)上傳", "0 KB/s"),
("網(wǎng)絡(luò)下載", "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 // 用于在更新時識別標(biāo)簽
};
this.Controls.Add(valueLabel);
yPos += labelHeight;
}
}
4.3 窗口拖拽功能
實現(xiàn)窗口拖拽移動:
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;
}
}
4.4 右鍵菜單切換模式
private void SetupContextMenu()
{
var contextMenu = new ContextMenuStrip();
var modeMenu = new ToolStripMenuItem("切換顯示模式");
var mode0 = new ToolStripMenuItem("CPU + 內(nèi)存圖表")
{
Checked = _displayMode == 0
};
mode0.Click += (s, e) => SwitchDisplayMode(0);
var mode1 = new ToolStripMenuItem("溫度 + 網(wǎng)絡(luò)圖表")
{
Checked = _displayMode == 1
};
mode1.Click += (s, e) => SwitchDisplayMode(1);
var mode2 = new ToolStripMenuItem("詳細(xì)信息列表")
{
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("關(guān)閉", null, (s, e) => this.Close());
this.ContextMenuStrip = contextMenu;
}
private void SwitchDisplayMode(int mode)
{
_displayMode = mode;
_settings.TaskbarWindowDisplayMode = mode;
// 保存配置
Utils.SettingsManager.Save(_settings);
// 重新創(chuàng)建界面
SetupWindow();
}
五、配置持久化
5.1 配置數(shù)據(jù)結(jié)構(gòu)
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;
}
5.2 JSON 序列化存儲
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;
}
六、開機自啟動
6.1 注冊表方式實現(xiàn)
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;
}
}
}
七、UI 布局優(yōu)化
7.1 避免控件重疊
在 WinForms 中,控件重疊是常見問題。需要精確計算每個控件的位置和大小:
// 使用固定列位置和行位置
int col1X = 15, col2X = 250, col3X = 485, col4X = 720;
int row1Y = 10, row2Y = 40, row3Y = 70, row4Y = 100;
// 創(chuàng)建信息標(biāo)簽時使用固定大小
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;
}
7.2 響應(yīng)式布局
使用 Anchor 屬性實現(xiàn)窗口大小改變時控件自適應(yīng):
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
};
八、系統(tǒng)托盤功能
8.1 托盤圖標(biāo)和菜單
private void SetupNotifyIcon()
{
_notifyIcon = new NotifyIcon
{
Icon = SystemIcons.Application,
Visible = true,
Text = "Windows 系統(tǒng)監(jiān)控"
};
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("顯示主窗口", null, (s, e) => ShowMainWindow());
contextMenu.Items.Add("任務(wù)欄窗口", 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();
}
8.2 窗口最小化到托盤
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();
}
}
總結(jié)
這個系統(tǒng)監(jiān)控工具的開發(fā)涉及了以下幾個關(guān)鍵技術(shù)點:
- 硬件數(shù)據(jù)采集:結(jié)合 PerformanceCounter 和 LibreHardwareMonitor 實現(xiàn)全面的硬件監(jiān)控
- 數(shù)據(jù)可視化:使用 ScottPlot 實現(xiàn)高性能的實時曲線繪制
- UI 設(shè)計:WinForms 布局優(yōu)化,避免控件重疊
- 數(shù)據(jù)管理:使用隊列管理歷史數(shù)據(jù),控制內(nèi)存占用
- 配置持久化:JSON 序列化存儲用戶配置
- 系統(tǒng)集成:托盤圖標(biāo)、開機自啟、懸浮窗口等系統(tǒng)功能
整個項目代碼結(jié)構(gòu)清晰,模塊化設(shè)計良好,后續(xù)可以方便地擴(kuò)展更多監(jiān)控項和功能。
運行截圖
主窗口展示了多個實時曲線圖表,任務(wù)欄小窗口可以自由拖拽并切換顯示模式,整體界面簡潔美觀,性能開銷低。
開發(fā)環(huán)境要求:
- Visual Studio 2022 或更高版本
- .NET 10.0 SDK
- Windows 10/11 操作系統(tǒng)
依賴包:
<PackageReference Include="LibreHardwareMonitorLib" Version="0.9.3" /> <PackageReference Include="ScottPlot.WinForms" Version="5.0.47" />
以上就是基于C# WinForms開發(fā)的Windows系統(tǒng)監(jiān)控工具的詳細(xì)內(nèi)容,更多關(guān)于C# WinForms Windows系統(tǒng)監(jiān)控的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#中nameof用法和應(yīng)用場景實現(xiàn)
在 C# 中,nameof是一個上下文關(guān)鍵字,用于在編譯時獲取,并以字符串形式返回,下面就來具體介紹一下如何使用,感興趣的可以了解一下2025-11-11
C#實現(xiàn)查殺本地與遠(yuǎn)程進(jìn)程的方法
這篇文章主要介紹了C#實現(xiàn)查殺本地與遠(yuǎn)程進(jìn)程的方法,可實現(xiàn)針對特定進(jìn)程的關(guān)閉操作,是C#進(jìn)程操作的一個典型應(yīng)用,需要的朋友可以參考下2014-12-12
C# Dynamic關(guān)鍵字之:dynamic為什么比反射快的詳解
本篇文章是對C#中dynamic為什么比反射快進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05

