你对则世界对 發表於 2025-12-25 08:58:27

基于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 &gt; 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 &amp;&amp; _networkReceivedCounter != null)
      {
            long bytesSent = (long)_networkSentCounter.NextValue();
            long bytesReceived = (long)_networkReceivedCounter.NextValue();

            var now = DateTime.Now;
            var timeDiff = (now - _lastNetworkUpdate).TotalSeconds;

            if (timeDiff &gt; 0 &amp;&amp; _lastBytesSent &gt; 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 &amp;&amp; sensor.Value.HasValue)
                {
                  data.CpuTemperature = Math.Max(data.CpuTemperature, sensor.Value.Value);
                }

                // 获取 CPU 主频
                if (sensor.SensorType == SensorType.Clock &amp;&amp;
                  sensor.Name.Contains("Core") &amp;&amp; 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 &amp;&amp; sensor.Value.HasValue)
                {
                  data.GpuTemperature = Math.Max(data.GpuTemperature, sensor.Value.Value);
                }

                if (sensor.SensorType == SensorType.Load &amp;&amp;
                  sensor.Name.Contains("Core") &amp;&amp; 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 &gt;= 0 &amp;&amp; status.BatteryLifePercent &lt;= 1 &amp;&amp;
      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&lt;float&gt; _cpuHistory;
    private readonly Queue&lt;float&gt; _memoryHistory;
    private readonly Queue&lt;float&gt; _cpuTempHistory;
    private readonly Queue&lt;float&gt; _gpuTempHistory;
    // ... 其他数据队列

    public DataHistory(int maxDataPoints = 60)
    {
      _maxDataPoints = maxDataPoints;
      _cpuHistory = new Queue&lt;float&gt;(maxDataPoints);
      _memoryHistory = new Queue&lt;float&gt;(maxDataPoints);
      // 初始化其他队列...
    }

    public void AddData(MonitorData data)
    {
      AddToQueue(_cpuHistory, data.CpuUsage);
      AddToQueue(_memoryHistory, data.MemoryUsage);
      AddToQueue(_cpuTempHistory, data.CpuTemperature);
      // 添加其他数据...
    }

    private void AddToQueue(Queue&lt;float&gt; queue, float value)
    {
      if (queue.Count &gt;= _maxDataPoints)
      {
            queue.Dequeue();
      }
      queue.Enqueue(value);
    }

    public double[] GetCpuHistory() =&gt; _cpuHistory.Select(x =&gt; (double)x).ToArray();
    public double[] GetMemoryHistory() =&gt; _memoryHistory.Select(x =&gt; (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 &gt; 0)
    {
      var signal1 = plot.Plot.Add.Signal(data1);
      signal1.Color = ScottColor.FromColor(color1);
      signal1.LineWidth = 2;
      signal1.LegendText = legend1;
    }

    if (data2.Length &gt; 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 &gt; 0 || data2.Length &gt; 0)
    {
      double maxValue = 0;
      if (data1.Length &gt; 0) maxValue = Math.Max(maxValue, data1.Max());
      if (data2.Length &gt; 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) =&gt; SwitchDisplayMode(0);

    var mode1 = new ToolStripMenuItem("温度 + 网络图表")
    {
      Checked = _displayMode == 1
    };
    mode1.Click += (s, e) =&gt; SwitchDisplayMode(1);

    var mode2 = new ToolStripMenuItem("详细信息列表")
    {
      Checked = _displayMode == 2
    };
    mode2.Click += (s, e) =&gt; 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) =&gt; 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&lt;AppSettings&gt;(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() =&gt; 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) =&gt; ShowMainWindow());
    contextMenu.Items.Add("任务栏窗口", null, (s, e) =&gt; ToggleTaskbarWindow());
    contextMenu.Items.Add(new ToolStripSeparator());
    contextMenu.Items.Add("退出", null, (s, e) =&gt; Application.Exit());

    _notifyIcon.ContextMenuStrip = contextMenu;
    _notifyIcon.DoubleClick += (s, e) =&gt; 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;">&lt;PackageReference Include="LibreHardwareMonitorLib" Version="0.9.3" /&gt;
&lt;PackageReference Include="ScottPlot.WinForms" Version="5.0.47" /&gt;
</pre></div>
<p>以上就是基于C# WinForms开发的Windows系统监控工具的详细内容,更多关于C# WinForms Windows系统监控的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>C#&nbsp;WinForms程序调用Python脚本的完整代码案例</li><li>使用C#和WinForms创建动态图表的两种方法</li><li>C#&nbsp;WinForms使用CyUSB.dll访问USB设备的实现步骤</li><li>C#&nbsp;WinForms存储过程操作数据库的实例讲解</li><li>C#&nbsp;WinForms中实现MD5的加密</li><li>C#&nbsp;WinForms控件拖动实现技巧</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: 基于C# WinForms开发的Windows系统监控工具