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.实现过程
随机推荐
- PostgreSQL数据库查询最近几天的数据
pgsql语法类似mysql ,下面总结几个pgsql工作会用到的求时间的语句 1.当前时间向前推一天\ SELECT current_timestamp - interval '1 day' 例: ...
- 蓝桥杯c语言基础题
问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少. 输入格式 输入包含一个整数n ...
- Python获取系统交互式shell,跨平台
本文地址:https://www.cnblogs.com/M4K0/p/9044237.html 昨天搞了半天,终于把这两个环节打通了.后续可以进一步调用adb命令执行一些操作,细节说明已在代码中添加 ...
- Mybatis 中的<![CDATA[ ]]>浅析
在使用mybatis 时我们sql是写在xml 映射文件中,如果写的sql中有一些特殊的字符的话,在解析xml文件的时候会被转义,但我们不希望他被转义,所以我们要使用<![CDATA[ ]]&g ...
- .NET Core ASP.NET Core Basic 1-2 控制反转与依赖注入
.NET Core ASP.NET Core Basic 1-2 本节内容为控制反转与依赖注入 简介 控制反转IOC 这个内容事实上在我们的C#高级篇就已经有所讲解,控制反转是一种设计模式,你可以这样 ...
- 【Java并发】线程的顺序执行
/** * 问题:有线程a.b.c,如何让它们顺序执行? * 方式一:可用Join()方法实现 * 方式二:可用newSingleThreadExecutor() * Created by Smile ...
- 文件系统【图片处理】(基于thumbnailator)典藏版-壹
很多系统开发中都会碰到文件相关的处理,最近顺手开发一个小型文件系统的过程中碰到图片缩略图的需求,需要在显示的时候提供缩略图,下载的时候提供原图,大家直接想到的可能是java自带的图片处理类,但是处理过 ...
- Reactive(2) 响应式流与制奶厂业务
目录 再谈响应式 为什么Web后端开发的,对 Reactive 没有感觉 Java 9 支持的 Reactive Stream 范例 小结 扩展阅读 再谈响应式 在前一篇文章从Reactive编程到& ...
- CF981C Useful Decomposition 树 dfs 二十三 *
Useful Decomposition time limit per test 1 second memory limit per test 256 megabytes input standard ...
- hotcss.js Flexible 移动端适配在dpr=2和dpr=3出现的字体大小设置不正确问题.
这段时间一直在用hotcss做移动端适配,做了几个页面没有发现什么问题,后来老大要加快进度,我把项目分出一块给另一个同事做,她发现了一个问题就是字体在dpr=2,dpr=3,的设备上字体大小显示老是不 ...