ReactiveUI:如何实现进程内存监控中ReactiveList的周期性刷新
嘿,作为Rx的新手,你这个需求简直是Rx的典型应用场景啊!定时异步更新、后台线程处理、自动管理订阅生命周期,Rx都能帮你优雅搞定。我来给你一步步拆解实现方案:
核心思路
我们可以利用Rx的Observable.Interval生成定时信号,结合线程调度器把监控逻辑放到后台执行,再切换回UI线程更新DataGrid。同时通过订阅的IDisposable对象,轻松实现复选框勾选/取消时的启停控制,还能自然处理进程退出的异常情况。
具体实现步骤
- 绑定复选框的勾选/取消事件,用来启动和停止Rx监控序列
- 用
Observable.Interval创建200ms间隔的触发信号,通过SubscribeOn指定后台线程池执行监控逻辑 - 每次触发时,遍历当前监控的进程,更新内存占用,同时过滤掉已退出的进程
- 用
ObserveOn把结果切换回UI线程,安全更新DataGrid的数据源
关键代码示例(以WPF为例)
using System.Reactive.Linq; using System.Reactive.Concurrency; using System.Diagnostics; using System.Windows; using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; // 进程信息模型:必须实现INotifyPropertyChanged,让UI自动更新 public class ProcessInfo : INotifyPropertyChanged { private int _processId; private string _processName; private long _memoryUsage; public int ProcessId { get => _processId; set { _processId = value; OnPropertyChanged(); } } public string ProcessName { get => _processName; set { _processName = value; OnPropertyChanged(); } } public long MemoryUsage { get => _memoryUsage; set { _memoryUsage = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } // 窗口ViewModel或后台代码 public class MainWindowViewModel : INotifyPropertyChanged { private IDisposable _monitorSubscription; public ObservableCollection<ProcessInfo> MonitoredProcesses { get; } = new(); // 复选框勾选事件处理 public void OnMonitorChecked() { // 初始加载目标进程(这里可以根据你的需求筛选,比如只监控特定名称的进程) var initialProcesses = Process.GetProcesses() .Where(p => !string.IsNullOrWhiteSpace(p.ProcessName)) .Select(MapToProcessInfo) .ToList(); // 初始化UI数据源 foreach (var proc in initialProcesses) { MonitoredProcesses.Add(proc); } // 创建Rx监控序列 _monitorSubscription = Observable.Interval(TimeSpan.FromMilliseconds(200)) .SubscribeOn(TaskPoolScheduler.Default) // 后台线程执行监控逻辑 .Select(_ => UpdateProcessMemory()) // 每次间隔触发时更新内存 .ObserveOn(Dispatcher.CurrentDispatcher) // 切回UI线程更新数据源 .Subscribe(updatedList => { // 更新现有进程的内存 foreach (var updatedProc in updatedList) { var target = MonitoredProcesses.First(p => p.ProcessId == updatedProc.ProcessId); target.MemoryUsage = updatedProc.MemoryUsage; } // 移除已退出的进程 var exitedIds = MonitoredProcesses.Select(p => p.ProcessId).Except(updatedList.Select(p => p.ProcessId)); foreach (var id in exitedIds.ToList()) { var exitedProc = MonitoredProcesses.First(p => p.ProcessId == id); MonitoredProcesses.Remove(exitedProc); } }, error => { // 处理异常(比如日志记录或弹窗提示) MessageBox.Show($"监控出错:{error.Message}"); }); } // 复选框取消事件处理 public void OnMonitorUnchecked() { // 取消订阅,停止监控 _monitorSubscription?.Dispose(); _monitorSubscription = null; // 清空数据源 MonitoredProcesses.Clear(); } // 辅助方法:将Process映射为ProcessInfo private ProcessInfo MapToProcessInfo(Process process) { return new ProcessInfo { ProcessId = process.Id, ProcessName = process.ProcessName, MemoryUsage = process.WorkingSet64 / 1024 / 1024 // 转换为MB }; } // 后台更新进程内存,过滤已退出的进程 private List<ProcessInfo> UpdateProcessMemory() { var updatedList = new List<ProcessInfo>(); foreach (var procInfo in MonitoredProcesses.ToList()) { try { using var process = Process.GetProcessById(procInfo.ProcessId); procInfo.MemoryUsage = process.WorkingSet64 / 1024 / 1024; updatedList.Add(procInfo); } catch (ArgumentException) { // 进程已退出,跳过该进程 continue; } } return updatedList; } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
关键注意事项
- 线程安全:必须用
SubscribeOn把监控逻辑放到后台线程,ObserveOn切回UI线程,避免UI卡顿和跨线程操作异常 - 订阅管理:一定要保存
IDisposable对象,取消勾选时调用Dispose(),防止内存泄漏 - 进程退出处理:捕获
ArgumentException(通过进程ID找不到进程时抛出),自动过滤已退出的进程 - UI自动更新:进程模型必须实现
INotifyPropertyChanged,这样DataGrid能自动刷新内存占用,不用手动重绘整个列表 - WinForms适配:如果是WinForms项目,把
ObserveOn(Dispatcher.CurrentDispatcher)换成ObserveOn(ControlScheduler.FromCurrentSynchronizationContext())即可
内容的提问来源于stack exchange,提问作者BertAR
相关产品推荐
相关产品推荐

