C#使用Oxyplot绘制监控界面
C#中可选的绘图工具有很多,除了Oxyplot还有DynamicDataDisplay(已经改名为InteractiveDataDisplay)等等。不过由于笔者这里存在一些环境上的特殊要求,.Net Framework的版本被限制在4,而InteractiveDataPlay要求的最低版本是4.5.2。所以选择了对版本要求较低的Oxyplot。
IDE为VS2012,创建工程后首先通过NuGet程序包管理器控制台,通过下述命令添加对Oxyplot的引用:
PM> Install-Package Oxyplot.Core
PM> Install-Package Oxyplot.Wpf
XAML里添加上必要的引用:
<Window x:Class="MonitorForm.MonitorForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MonitorForm"
xmlns:oxy="http://oxyplot.org/wpf"
Title="MainWindow" Height="350" Width="525">
<Grid>
<oxy:PlotView Model="{Binding Path= SimplePlotModel}"></oxy:PlotView> </Grid>
</Window>
笔者的开发场景是需要统计四类数据,因此开放四个公共方法供外部调用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading; namespace MonitorForm { /// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MonitorForm : Window { private PlotViewModel _viewModel; public MonitorForm() { InitializeComponent(); _viewModel = new PlotViewModel();
this.DataContext = _viewModel;
} public void addSendCount(int iCount) { _viewModel.addSendCount(iCount);
} public void addUnsendCount(int iCount) { _viewModel.addUnsendCount(iCount);
} public void addConfirmCount(int iCount) { _viewModel.addConfirmCount(iCount);
} public void addDealCount(int iCount) { _viewModel.addDealCount(iCount);
}
}
}
MVVM模式,需要添加ViewModel层:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OxyPlot;
using OxyPlot.Series;
using OxyPlot.Axes;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent; namespace MonitorForm { public class PlotViewModel { /// <summary>
/// 画直线
/// </summary>
public PlotModel SimplePlotModel { get; set; } //每条线对应一个队列用作实时数据统计
private ConcurrentQueue<int> queueSend = new ConcurrentQueue<int>();
private ConcurrentQueue<int> queueUnsend = new ConcurrentQueue<int>();
private ConcurrentQueue<int> queueConfirm = new ConcurrentQueue<int>();
private ConcurrentQueue<int> queueDeal = new ConcurrentQueue<int>(); public void addSendCount(int iCount) { queueSend.Enqueue(iCount);
} public void addUnsendCount(int iCount) { queueUnsend.Enqueue(iCount);
} public void addConfirmCount(int iCount) { queueConfirm.Enqueue(iCount);
} public void addDealCount(int iCount) { queueDeal.Enqueue(iCount);
} public int getSendCount() { int iSingle = ;
int iTotal = ;
while (queueSend.TryDequeue(out iSingle)) { iTotal += iSingle;
} return iTotal;
} public int getUnsendCount() { int iSingle = ;
int iTotal = ;
while (queueUnsend.TryDequeue(out iSingle)) { iTotal += iSingle;
} return iTotal;
} public int getConfirmCount() { int iSingle = ;
int iTotal = ;
while (queueConfirm.TryDequeue(out iSingle)) { iTotal += iSingle;
} return iTotal;
} public int getDealCount() { int iSingle = ;
int iTotal = ;
while (queueDeal.TryDequeue(out iSingle)) { iTotal += iSingle;
} return iTotal;
} public PlotViewModel() { SimplePlotModel = new PlotModel(); //创建于建立初始化数据节点
var lineSend = new LineSeries() { Title = "报送" };
lineSend.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), ));
SimplePlotModel.Series.Add(lineSend); var lineUnsend = new LineSeries() { Title = "待报送" };
lineUnsend.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), ));
SimplePlotModel.Series.Add(lineUnsend); var lineConfirm = new LineSeries() { Title = "确认" };
lineConfirm.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), ));
SimplePlotModel.Series.Add(lineConfirm); var lineDeal = new LineSeries() { Title = "成交" };
lineDeal.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), ));
SimplePlotModel.Series.Add(lineDeal); //定义y轴
LinearAxis leftAxis = new LinearAxis() { Position = AxisPosition.Left,
Minimum = ,
Maximum = ,
Title = "笔数",//显示标题内容
TitlePosition = ,//显示标题位置
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.None,
}; //定义x轴 报盘监控界面x轴统一为时间
DateTimeAxis bottomAxis = new DateTimeAxis() { Position = AxisPosition.Bottom,
StringFormat = "hh:mm:ss",
Minimum = DateTimeAxis.ToDouble(DateTime.Now),
Maximum = DateTimeAxis.ToDouble(DateTime.Now.AddMinutes()),
Title = "时间",
TitlePosition = ,
IntervalLength = ,
MinorIntervalType = DateTimeIntervalType.Seconds,
IntervalType = DateTimeIntervalType.Seconds,
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.None,
}; SimplePlotModel.Axes.Add(leftAxis);
SimplePlotModel.Axes.Add(bottomAxis); bool bToMove = false;
Task.Factory.StartNew(() => { while (true) { lineSend.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), getSendCount()));
lineUnsend.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), getUnsendCount()));
lineConfirm.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), getConfirmCount()));
lineDeal.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), getDealCount())); if (!bToMove) { //当前时间减去起始时间达到30秒后开始左移时间轴
TimeSpan timeSpan = DateTime.Now - DateTimeAxis.ToDateTime(bottomAxis.Minimum);
if (timeSpan.TotalSeconds >= ) { bToMove = true;
}
} else { //左移时间轴,跨度维持在60秒
bottomAxis.Minimum = DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(-));
bottomAxis.Maximum = DateTimeAxis.ToDouble(DateTime.Now.AddSeconds()); //删除历史节点,防止DataPoint过多影响效率,也防止出现内存泄漏
lineSend.Points.RemoveAt();
lineConfirm.Points.RemoveAt();
lineUnsend.Points.RemoveAt();
lineDeal.Points.RemoveAt();
} //根据报单笔数判断是否需要更新y轴刻度 //首先找出四条统计线中当前最大的节点
double iMax = lineSend.MaxY;
if (iMax < lineConfirm.MaxY) {
iMax = lineConfirm.MaxY;
}
if (iMax < lineUnsend.MaxY) {
iMax = lineUnsend.MaxY;
}
if (iMax < lineDeal.MaxY) {
iMax = lineDeal.MaxY;
} //如果当前的y轴最大刻度小于数据集中的最大值,放大
leftAxis.Maximum = iMax + ( - iMax % );
leftAxis.IntervalLength = leftAxis.Maximum / ; //每秒刷新一次视图
SimplePlotModel.InvalidatePlot(true);
Thread.Sleep();
}
});
}
}
}
从上述代码可以看出,功能主要为实现了Y轴为笔数统计,而X轴为时间轴且当线画到了中间时开始左移时间轴。统计的间隔为1秒。
如果要导出DLL封装给其他程序使用的话,在项目属性中将输出类型调整为类库即可。这时可能会有例如不存在InitializeComponent()之类的报错,将App.xmal属性中的生成操作修改成无即可顺利导出。
自己写了个小DEMO调用该DLL,不停往里添加数据,效果图如下:

时间轴会左移,而Y轴的笔数统计也会根据当前DataPoint集合中的最大值进行相应的调整。

C#使用Oxyplot绘制监控界面的更多相关文章
- 【Java框架型项目从入门到装逼】第八节 - 用EasyUI绘制主界面
1.引入资源包 在上一节中,我们把基本的框架都搭好了,用了Spring,SPringMVC.这一节,我们先来画页面,前端框架采用EasyUI来实现. easyui是一种基于jQuery的用户界面插件集 ...
- SpringBoot2.0 基础案例(07):集成Druid连接池,配置监控界面
一.Druid连接池 1.druid简介 Druid连接池是阿里巴巴开源的数据库连接池项目.Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能.功能强大,能防SQL注入,内置Login ...
- 六:SpringBoot-集成Druid连接池,配置监控界面
SpringBoot-集成Druid连接池,配置监控界面 1.Druid连接池 1.1 Druid特点 2.SpringBoot整合Druid 2.1 引入核心依赖 2.2 数据源配置文件 2.3 核 ...
- kafka-eagle监控界面搭建
kafka-eagle监控界面搭建 一.背景 二 .mac上安装kafka-eagle 1.安装JDK 2.安装eagle 1.下载eagle 2.解压并配置环境变量 3.启用kafka的JMX 4. ...
- AspNet Core下利用 app-metrics+Grafana + InfluxDB实现高大上的性能监控界面
在日常系统工作中,我们为了洞察系统的问题和运作情况通常会记录日志的方式来进行分析,但是在很多情况下都是被动的在出问题后才会去查日志.在很多时候,我们可能更需要相对实时的了解整个系统或者某一时段的运行的 ...
- zabbix结合grafana打造炫酷监控界面
一.grafana介绍 grafana是一个开源的数据展示工具, 是一个开箱即用的可视化工具,具有功能齐全的度量仪表盘和图形编辑器,有灵活丰富的图形化选项,可以混合多种风格,支持多个数据源特点. za ...
- MFC 监控界面上所有文本框值的变化
//控件消息,菜单,按钮等 BOOL CXXDlg::OnCommand(WPARAM wParam, LPARAM lParam) { // TODO: 在此添加专用代码和/或调用基类 int wm ...
- druid 配置监控界面和开启spring支持
1.配置监控页面 <!-- JNDI方式配置数据源 --> <!-- <bean id="dataSource" class="org.sprin ...
- 利用微信小程序实现web监控界面
1.实现思路 利用小程序去调用公司zabbix的接口获取网站监控数据并展示出来. 2.准备阶段 1.小程序公众号 2.企业号 3.zabbix接口 3.实现过程
随机推荐
- 合并多个jar包,并通过私服依赖
背景:许多jar包在maven仓库中没有,项目如果添加了许多的本地jar包,别人拿到代码也无法编译 需求:将本地jar包上传至私服并设置依赖,如果jar包较多,但都从属于同一功能,需要合并为一个jar ...
- .NET导出Excel的四种方法及评测
.NET导出Excel的四种方法及评测 导出Excel是.NET的常见需求,开源社区.市场上,都提供了不少各式各样的Excel操作相关包.本文,我将使用NPOI.EPPlus.OpenXML.Aspo ...
- python 31 升级版解决粘包现象
目录 1. recv 工作原理 2.升级版解决粘包问题 3. 基于UDP协议的socket通信 1. recv 工作原理 1.能够接收来自socket缓冲区的字节数据: 2.当缓冲区没有数据可以读取时 ...
- Java虚拟机详解(八)------虚拟机监控和分析工具(2)——可视化
上篇博客我们介绍了虚拟机监控和分析命令行工具,由于其不够直观,不是很容易排查问题,那么本篇博客我们就来介绍几个可视化工具. 1.JConsole JConsole(Java Monitoring an ...
- ZooKeeper异步调用命令
在ZooKeeper中,所有的同步调用命令,都会有一个相应的异步调用方法.异步调用能在一个单独线程中同时提交更多的命令,也能在一定程度上简化代码实现. 1 异步create方法 如创建zNode的命令 ...
- Kubernetes 弹性伸缩全场景解读(五) - 定时伸缩组件发布与开源
作者| 阿里云容器技术专家刘中巍(莫源) 导读:Kubernetes弹性伸缩系列文章为读者一一解析了各个弹性伸缩组件的相关原理和用法.本篇文章中,阿里云容器技术专家莫源将为你带来定时伸缩组件 kub ...
- MyBatis_Generator (MBG)逆向工程的四种方式
mybatis是目前很流行的持久层框架,其逆向工程更是大大缩减了我们的开发时间.有兴趣的可以看文档. 文档地址: http://www.mybatis.org/generator/index.html ...
- macOS平台下Qt应用程序菜单翻译及调整
一.翻译 在macOS平台上,系统会为应用程序菜单添加一些额外的菜单项.先来看一些典型的例子: 这个是Qt Creator的菜单,系统为应用程序菜单添加了一些桌面显示操作相关的菜单项: 这个是Qt D ...
- Codeforces Round #503 (by SIS, Div. 2) D. The hat -交互题,二分
cf1020D 题意: 交互题目,在有限的询问中找到一个x,使得数列中的第x位和第(x+n/2)位的值大小相同.数列保证相邻的两个差值为1或-1: 思路: 构造函数f(x) = a[x] - a[x ...
- poj 3177 Redundant Paths(tarjan边双连通)
题目链接:http://poj.org/problem?id=3177 题意:求最少加几条边使得没对点都有至少两条路互通. 题解:边双连通顾名思义,可以先求一下连通块显然连通块里的点都是双连通的,然后 ...