Nursery是一个简单的进程托管Demo,用于启动console应用程序。
问题
CheckBoxList
这里一开始用的是ObservableCollection的方式,后感感觉太过于繁杂,改为直接向ListBox
中添加CheckBox
:ProcessListBox.Items.Add(checkBox);
。
ListView的动态更新
或许有用的资料 1. CheckBoxList(ObservableCollection)in WPF 2. WPF ListView实时更新及INotifyPropertyChanged使用演示 3. WPF Listview绑定数据发生改变后前端没有更新
尝试
这里想的是另起一个监控线程,对线程的实时信息进行更新。对infoList
更新后,通过ProcessInformationListView.ItemsSource = infoList;
使其生效,但是遇到了线程间对对象访问的问题:
System.InvalidOperationException:“调用线程无法访问此对象,因为另一个线程拥有该对象。
ProcessInformationListView.Dispatcher.BeginInvoke(new Action(() => |
ListView
的内容并不会更改。不仅如此,monitor执行后主线程不能向ListView中添加内容了,如果先添加了内容,monitor执行后内容不会改变。
最终解决方式
LIstView
的数据源使用ObservableCollection
:private ObservableCollection<ProcessInformation> InfoList { get; set; }
- 实体类
ProcessInformation
继承INotifyPropertyChanged
接口public class ProcessInformation : INotifyPropertyChanged
{
private string _Process;
private int _PID;
private string _CPU;
private string _Memory;
public event PropertyChangedEventHandler PropertyChanged;
public string Process {
get { return _Process; }
set { _Process = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Process"));
}
}
public int PID {
get { return _PID; }
set { _PID = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PID"));
}
}
public string CPU {
get { return _CPU; }
set { _CPU = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CPU"));
}
}
public string Memory {
get { return _Memory; }
set { _Memory = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Memory"));
}
}
} - 跨线程访问(这个就不用了,因为
ObservableCollection
实现了INotifyPropertyChanged
接口,当InfoList
发生改变时会自动更新ListView
,不用手动更新ListView.ItemsSource
,也就不会发生跨线程访问ListView
了。ps: 好像是跨线程更改前台的数据才会出现这个问题) 不更新、不能添加GridView
的原因也应该是没有实现INotifyPropertyChanged
接口
ProcessInformationListView.Dispatcher.BeginInvoke(new Action(() => |
不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改
private ObservableCollection<ProcessInformation> infoList { get; set; } |
System.NotSupportedException:“该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。”
ObservableCollection
类型的CollectionView
不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。(我也不懂是哪个线程对该对象进行了访问,不是我的监控线程)
解决方式:
ThreadPool.QueueUserWorkItem(delegate |
NotifyIcon
程序托盘图标用的是HandyControl的控件。 根据文档编辑图标、绑定事件即可。
<hc:NotifyIcon x:Name="NotifyIcon" Text="ProcessNursery" |
NLog的日志系统,主要是调试时候找问题的。
分为以下几种日志等级:
Trace
Debug
Info
Warn
Error
Fatal
配置
NLog使用需要添加配置文件,可以添加到App.config
,也可以新建NLog.config
然后添加内容。我手动新建配置文件之后使用不了,使用NuGet命令添加成功。(工具->NuGet 包管理器->程序包管理器控制台,输入Install-Package NLog.Config [-Version 4.7.5]
)。关于自定义日志,可以看这里
|
使用
private static Logger logger = LogManager.GetCurrentClassLogger(); |
进程的CPU与内存
使用.Net的PerformanceCounter
类型对进程的性能进行监控
Process process = pNersury[fileName].process; |
实时获取子进程的输出
参考: 1. 启动一个进程并实时获取状态信息 2. c# - 从Process获取实时输出
UseShellExecute
必须为false
,不然无法在代码中读标准。 RedirectStandardOutput
必须为true
,这样我们才能在代码中访问标准流。 EnableRaisingEvents
必须为true
,这样才会引发OutputDataReceived
和Exited
解决方式是两条内容的结合:
Process child = new Process(); |