wpfmvvm,C#/WPF/MVVM 网卡流量监控器 by Mgen

文章仅讲程序中一些需要注意的地方,其中.NET中的PerformanceCounter占主要部分,感兴趣的话,可以下载源代码作参考。
目录
  • 截图和下载
  • 简述Windows和.NET中的性能监控概念
  • 使用.NET中的PerformanceCounter
  • MVVM:绑定ICommand集合
  • 线程安全的ObservableCollection
  • 关于图表

 
 
 
返回目录

截图和下载

 
imageC#/WPF/MVVM 网卡流量监控器 by Mgenwpfmvvm
注:程序在我的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性能监视器中添加计数器)
imageimageC#/WPF/MVVM 网卡流量监控器 by Mgenwpfmvvm
 
.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 Update;
        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 _Commands;
        public ReadOnlyCollection Commands
        {
            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直接绑定命令:
                        Focusable="False">
           
               
                   

最新评论

发表评论