目录
- 截图和下载
- 简述Windows和.NET中的性能监控概念
- 使用.NET中的PerformanceCounter
- MVVM:绑定ICommand集合
- 线程安全的ObservableCollection
- 关于图表
返回目录
截图和下载
注:程序在我的Windows 7下工作得很好,不过没有在Windows XP做下测试。
下载程序或源代码
点击下载
(此为微软SkyDrive存档,请用浏览器直接下载,用某些下载工具可能无法下载)
程序环境:.NET Framework 4.0 Client Profile
源代码环境:Visual C# 2010 Express SP1
返回目录
简述Windows和.NET中的性能监控概念
Windows中的性能监控器可以提供软硬件的一些实时运行状况信息,网络监控相关得性能监视器是属于Network Interface类,程序中使用Bytes Received/sec和Bytes Sent/sec计数器(Counter)来得到相应网卡得接收和发送字节数(可以约等于下载和上传量),监控器类中的实例就是系统已知网卡接口(有些可能是虚拟网卡,不一定全是物理硬件网卡)。这三个概念是很重要的,比如具另外一个例子:进行操作系统进程的线程数查询,那么性能监控器类就是Process,计数器名称是Process类中的ThreadCount,实例就是进程名称。当然某些性能监控类也有可能没有实例的。
在控制面板-管理工具中可以打开性能监控器。或者在运行中输入perfmon(Performance Monitor)
(下图:在Windows性能监视器中添加计数器)
.NET提供对Windows性能监控器的包装,相应类型都位于System.Diagnostics命名空间下,而且在System.dll内(不需要额外加引用)。
性能监控器中的“性能监控器类型”和“性能计数器名称”直接对应System.Diagnostics下的PerformanceCounterCategory和PerformanceCounter类。至于性能监控器的实例名称,可以从PerformanceCounterCategory的GetInstanceNames方法中得到。
返回目录
使用.NET中的PerformanceCounter
.NET中的PerformanceCounter提供了很好的API包装,使用起来非常方便。首先,把要用到的字段创建好(包括PerformanceCounter对象和需要用到的监控器名称):
const string Network = "Network Interface";
const string Recv = "Bytes Received/sec";
const string Sent = "Bytes Sent/sec";
PerformanceCounterCategory category;
接下来做一些判断,如果系统找不到相应的监视计数器,那么抛出异常。如果没错的话,创建一个PerformanceCounterCategory。
if (!PerformanceCounterCategory.Exists(Network)
|| !PerformanceCounterCategory.CounterExists(Recv, Network)
|| !PerformanceCounterCategory.CounterExists(Sent, Network))
{
throw new InvalidOperationException("您的系统没有相关性能监视项存在");
}
category = new PerformanceCounterCategory(Network);
接着怎样得到系统网卡名称?其实上面已经提到过,调用PerformanceCounterCategory的GetInstanceNames方法,它返回字符串数组。
category.GetInstanceNames();
最后监控执行,我们把得到的数据存到一个自定义的EventArgs中:
class NicDataEventArgs : EventArgs
{
//接收字节
public float Recv { get; private set; }
//发送字节
public float Sent { get; private set; }
public NicDataEventArgs(float recv, float sent)
{
Recv = recv;
Sent = sent;
}
}
执行代码:
public event EventHandler
protected virtual void _disibledevent=>NicDataEventArgs args)
{
if (Update != null)
Update(this, args);
}
public void Start(string ins)
{
Initialize();
//建立两个PerformanceCounter来分别对应接收和发送监控
var crecv = new PerformanceCounter(Network, Recv, ins);
var csent = new PerformanceCounter(Network, Sent, ins);
while (true)
{
//得到下一个值
var valrecv = crecv.NextValue();
var valsent = csent.NextValue();
//发送事件数据
_disibledevent=>new NicDataEventArgs(valrecv, valsent));
//等待1秒
System.Threading.Thread.Sleep(1000);
}
}
注:上面while循环下有一个当前线程等待一秒的语句,根据微软BCL团队的建议,一个PerformanceCounter的下一个值的调用最好等待1秒或更长,因为某些PerformanceCounter的下一个值需要上一个值,而如果在短时间内连续调用PerformanceCounter.NextValue()可能会使两个值一样,从而出现不可预测的结果。
参考连接:http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx
注:上面代码为了解释会和程序实际代码有一些小差别,不过整体逻辑不变。
返回目录
MVVM:绑定ICommand集合
MVVM真是一种很令人惊奇的模式,程序中的执行按钮完全是来自一个命令集合,WPF中的命令对象来自ICommand对象,我们用RelayCommand并且加入Text属性,类似与RoutedUICommand.Text的属性。然后把所以命令加入到集合中,在界面中绑定命令集合就可以了。(RelayCommand来自:http://msdn.microsoft.com/en-us/magazine/dd419663.aspx)
命令集合这样被生成:
ReadOnlyCollection
public ReadOnlyCollection
{
get
{
if (_Commands == null)
{
_Commands = new ReadOnlyCollection
new List
{
new RelayCommandWithText(obj => Start(), obj => !IsStarted && ValidateData()) { Text = "开始" } ,
new RelayCommandWithText(obj => Stop(), obj => IsStarted) { Text = "停止" } ,
new RelayCommandWithText(obj => Refresh()) { Text = "刷新网络设备" }
});
}
return _Commands;
}
}
界面上ListBox直接绑定命令:
Margin="5" MinWidth="60"/>
于是程序那3个按钮就出现了,并且什么时候IsEnabled该为true,什么时候该为false都工作得很好(感谢ICommand.CanExecute事件),不觉得很神奇吗?
返回目录
线程安全的ObservableCollection
主ViewModel接收数据的方法是来自另一个线程调用,因此这个线程无法修改ObservableCollection,因为此动作会引发主界面更新,而一个WPF Dispatcher只能跟随一个线程。当然使用Dispatcher.BeginInvoke/Invoke可以解决问题,不过有的时候一个线程安全的ObservableCollection可能给看起来更舒服……程序中使用一个叫SafeObservable的泛型类(继承IList
返回目录
关于图表
图表控件来自WPF Toolkit开源框架(http://wpf.codeplex.com/)其中制图表需要引用System.Windows.Controls.DataVisualization.Toolkit.dll,程序直接把System.Windows.Controls.DataVisualization.Toolkit.dll和WPFToolkit.dll直接拷贝到本地并引用,因此不需要安装WPF Toolkit也可以运行。
最新评论