You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF MVVM下集合快速变更导致CPU占用过高、UI近乎冻结问题

根据你的需求,我整理了一套基于MVVM、MVVM Light的Windows进程监控实现方案,完美匹配任务管理器的核心功能(实时内存显示、进程启停监控),具体如下:

核心实现方案

1. 定义进程数据模型(Model层)

首先需要一个封装进程关键信息的模型类,借助MVVM Light的ObservableObject实现属性变更通知,确保内存占用变化能实时同步到UI:

using System.Diagnostics;
using GalaSoft.MvvmLight;

public class ProcessInfo : ObservableObject
{
    private int _id;
    private string _processName;
    private long _privateWorkingSetMB;
    private Process _process;

    public int Id
    {
        get => _id;
        set => Set(ref _id, value);
    }

    public string ProcessName
    {
        get => _processName;
        set => Set(ref _processName, value);
    }

    // 私有工作集,转换为MB单位
    public long PrivateWorkingSetMB
    {
        get => _privateWorkingSetMB;
        set => Set(ref _privateWorkingSetMB, value);
    }

    public Process Process
    {
        get => _process;
        set => Set(ref _process, value);
    }
}

2. ViewModel层实现核心业务逻辑

ViewModel作为逻辑核心,负责处理进程加载、实时更新、启停监控三个核心任务,继承MVVM Light的ViewModelBase:

2.1 基础属性与命令初始化

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Timers;
using System.Linq;

public class MainViewModel : ViewModelBase
{
    private bool _isMonitoring;
    private ObservableCollection<ProcessInfo> _monitoredProcesses;
    private Timer _memoryUpdateTimer;
    private Timer _processWatchTimer;
    // 目标进程名,这里以Chrome为例,可按需修改
    private readonly string _targetProcessName = "chrome";

    // 绑定复选框的监控开关
    public bool IsMonitoring
    {
        get => _isMonitoring;
        set
        {
            Set(ref _isMonitoring, value);
            value ? StartMonitoring() : StopMonitoring();
        }
    }

    // 绑定DataGrid的进程集合
    public ObservableCollection<ProcessInfo> MonitoredProcesses
    {
        get => _monitoredProcesses;
        set => Set(ref _monitoredProcesses, value);
    }

    // 切换监控状态的命令
    public ICommand ToggleMonitoringCommand { get; }

    public MainViewModel()
    {
        MonitoredProcesses = new ObservableCollection<ProcessInfo>();
        ToggleMonitoringCommand = new RelayCommand(() => IsMonitoring = !IsMonitoring);
        
        // 1秒更新一次内存,和任务管理器频率一致
        _memoryUpdateTimer = new Timer(1000);
        _memoryUpdateTimer.Elapsed += UpdateProcessMemoryUsage;
        
        // 2秒扫描一次进程启停,平衡性能与实时性
        _processWatchTimer = new Timer(2000);
        _processWatchTimer.Elapsed += CheckProcessStartsAndExits;
    }
}

2.2 启动监控与加载初始进程

private void StartMonitoring()
{
    // 加载当前已运行的目标进程
    LoadExistingTargetProcesses();
    _memoryUpdateTimer.Start();
    _processWatchTimer.Start();
}

private void LoadExistingTargetProcesses()
{
    foreach (var process in Process.GetProcessesByName(_targetProcessName))
    {
        AddProcessToCollection(process);
    }
}

private void AddProcessToCollection(Process process)
{
    try
    {
        // 捕获无权限访问的进程(比如系统核心进程)
        var procInfo = new ProcessInfo
        {
            Id = process.Id,
            ProcessName = process.ProcessName,
            PrivateWorkingSetMB = process.PrivateMemorySize64 / 1024 / 1024,
            Process = process
        };
        MonitoredProcesses.Add(procInfo);
    }
    catch (System.ComponentModel.Win32Exception)
    {
        // 可在这里记录日志或忽略无权限进程
    }
}

2.3 实时更新内存占用

private void UpdateProcessMemoryUsage(object sender, ElapsedEventArgs e)
{
    // 必须在UI线程更新UI元素,借助MVVM Light的DispatcherHelper
    DispatcherHelper.CheckBeginInvokeOnUI(() =>
    {
        for (int i = MonitoredProcesses.Count - 1; i >= 0; i--)
        {
            var procInfo = MonitoredProcesses[i];
            try
            {
                if (!procInfo.Process.HasExited)
                {
                    procInfo.Process.Refresh();
                    procInfo.PrivateWorkingSetMB = procInfo.Process.PrivateMemorySize64 / 1024 / 1024;
                }
                else
                {
                    MonitoredProcesses.Remove(procInfo);
                }
            }
            catch
            {
                // 进程无法访问时直接移除
                MonitoredProcesses.Remove(procInfo);
            }
        }
    });
}

2.4 监控进程启停

private void CheckProcessStartsAndExits(object sender, ElapsedEventArgs e)
{
    DispatcherHelper.CheckBeginInvokeOnUI(() =>
    {
        var currentProcessIds = MonitoredProcesses.Select(p => p.Id).ToHashSet();
        var runningTargetProcesses = Process.GetProcessesByName(_targetProcessName);

        // 新增刚启动的进程
        foreach (var process in runningTargetProcesses)
        {
            if (!currentProcessIds.Contains(process.Id))
            {
                AddProcessToCollection(process);
            }
        }

        // 移除已退出的进程(双重校验,确保无遗漏)
        for (int i = MonitoredProcesses.Count - 1; i >= 0; i--)
        {
            var procInfo = MonitoredProcesses[i];
            if (procInfo.Process.HasExited || !runningTargetProcesses.Any(p => p.Id == procInfo.Id))
            {
                MonitoredProcesses.Remove(procInfo);
            }
        }
    });
}

2.5 停止监控与资源释放

private void StopMonitoring()
{
    _memoryUpdateTimer.Stop();
    _processWatchTimer.Stop();
    MonitoredProcesses.Clear();
}

// 记得在ViewModel销毁时释放资源
public override void Cleanup()
{
    _memoryUpdateTimer.Dispose();
    _processWatchTimer.Dispose();
    base.Cleanup();
}

3. View层(XAML)实现

DataGrid绑定进程集合,复选框绑定监控开关,实现UI与逻辑的解耦:

<Window x:Class="ProcessMonitor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:ProcessMonitor.ViewModels"
        Title="进程监控工具" Height="450" Width="800">
    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>
    <Grid Margin="10">
        <StackPanel>
            <CheckBox Content="监控Chrome进程" IsChecked="{Binding IsMonitoring}" Margin="0 0 0 10" />
            <DataGrid ItemsSource="{Binding MonitoredProcesses}" AutoGenerateColumns="False" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="进程名称" Binding="{Binding ProcessName}" Width="*" />
                    <DataGridTextColumn Header="私有工作集(MB)" Binding="{Binding PrivateWorkingSetMB}" Width="150" />
                    <DataGridTextColumn Header="进程ID" Binding="{Binding Id}" Width="100" />
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Grid>
</Window>

4. 关键注意事项

  • UI线程初始化:记得在App.xaml.cs的OnStartup方法中初始化DispatcherHelper:DispatcherHelper.Initialize();
  • 性能优化:如果需要监控大量进程,建议用WMI事件监听(Win32_ProcessStartTrace和Win32_ProcessStopTrace)替代定时扫描,减少系统开销
  • 权限处理:部分系统进程需要管理员权限才能访问,可在项目属性中设置“需要管理员权限”

内容的提问来源于stack exchange,提问作者BertAR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:36:24