前言
现目需要在软件界面上实时显示数据的变化,实现类似心电图的效果,发现WPF似乎没有自带的图表控件。于是上网搜索了一下,发现了Live Charts这个开源项目,这里记录一下自己的使用方法。
简介
.Net的简单,灵活,交互式和强大的数据可视化。
LiveCharts只是数据可视化,但适用于所有人。
Live Charts是一个使用C\#,可以在WPF、UWP和WinForm上应用的图表控件。它支持各种自定义设置以及动画,可以实现丰富的效果,使用起来也较为方便。同时官网上有大量的教程与示例。
官网:https://lvcharts.net
教程与示例:https://lvcharts.net/App/examples/wpf/start
本文章主要尝试模拟一个记录图像光流角度和模值的动态折线图,当后台数据更新时,自动更新到图表上。
使用
安装
打开Visual Studio,新建一个WPF应用。
在右侧解决方案资源管理器中右键项目,选择“管理NuGet程序包”。搜索LiveCharts,安装LiveCharts和LiveCharts.Wpf。
编写控件
右键工程项目,添加新建项,选择用户控件。
XAML
<UserControl x:Class="ConstantChanges.ConstantChangesChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:constantChanges="clr-namespace:ConstantChanges"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance constantChanges:ConstantChangesChart}">
<Grid>
<!--此处禁用datatooltip,动画速度单位是时:分:秒-->
<lvc:CartesianChart AnimationsSpeed="0:0:0.2" Hoverable="False" DataTooltip="{x:Null}">
<!--曲线-->
<lvc:CartesianChart.Series>
<!--曲线1参数-->
<lvc:LineSeries x:Name="linePhase"
Values="{Binding PhaseChartValues}"
PointGeometry="{x:Static lvc:DefaultGeometries.Circle}"
PointGeometrySize="10"
LineSmoothness="1"
StrokeThickness="3"
Stroke="#00CCFF"
Fill="Transparent"></lvc:LineSeries>
<!--曲线2参数-->
<lvc:LineSeries x:Name="lineModlus"
Values="{Binding ModulusChartValues}"
PointGeometry="{x:Static lvc:DefaultGeometries.Square}"
PointGeometrySize="10"
LineSmoothness="0"
StrokeThickness="3"
Stroke="#FF3300"
Fill="Transparent"
ScalesYAt="1"></lvc:LineSeries>
</lvc:CartesianChart.Series>
<!--X坐标轴-->
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="帧">
<lvc:Axis.Separator>
<lvc:Separator IsEnabled="False" Step="1"></lvc:Separator>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<!--两条Y坐标轴-->
<lvc:CartesianChart.AxisY>
<lvc:Axis x:Name="axisPhase"
Foreground="DodgerBlue"
Title="角度"
MaxValue="7"
MinValue="0">
</lvc:Axis>
<lvc:Axis x:Name="axisModlus"
Foreground="IndianRed"
Title="模值"
Position="RightTop"
MaxValue="10"
MinValue="0">
</lvc:Axis>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
</Grid>
</UserControl>
其中曲线部分参数:
Values
:绑定C\#代码中的实际数据值 。PointGeometry
:数据点的外观。{x:Null}
即不标出,只显示曲线。{x:Static lvc:DefaultGeometries.Circle}
则将数据点用圆形标出。形状有Circle
、Cross
、Diamond
、Square
、Triangle
可选。PointGeometrySize
:数据点形状的大小。LineSmoothness
:曲线是否圆滑。如为1
则圆滑曲线,为0
则不圆滑,为折线。StrokeThickness
:曲线粗细程度,越大越粗。Stroke
:曲线颜色。Fill
:曲线下方填充颜色。Transparent
透明,即不填充。ScalesYAt
:曲线对应Y坐标轴,序号从0
开始,默认0
。
坐标轴参数:
Title
:坐标轴名称。Foreground
:名称和刻度的颜色。Position
:坐标轴位置。MaxValue
:最大值,不写则会根据数据自动变化。MinValue
:最小值,同上。Separator
:网格线,IsEnabled
决定是否显示,Step
为网格一格的大小,不写则自动。Labels
:标签。LabelFormatter
:标签格式,如把数值格式化为时间,详见官网教程。
C\# Code
using System.Windows.Controls;
using LiveCharts;
using LiveCharts.Configurations;
namespace ConstantChanges
{
// 数据点格式
public class MeasureModel
{
public int Index { get; set; }
public float Value { get; set; }
}
public partial class ConstantChangesChart : UserControl
{
private int _index;
public ChartValues<MeasureModel> PhaseChartValues { get; set; }
public ChartValues<MeasureModel> ModulusChartValues { get; set; }
public float PhaseValue { get; set; }
public float ModulusValue { get; set; }
// 当数值被更改时,触发更新
public int Index
{
get { return _index; }
set
{
_index = value;
Read();
}
}
public ConstantChangesChart()
{
InitializeComponent();
// 设置图表的XY和数值对应
var mapper = Mappers.Xy<MeasureModel>()
.X(model => model.Index)
.Y(model => model.Value);
Charting.For<MeasureModel>(mapper);
PhaseChartValues = new ChartValues<MeasureModel>();
ModulusChartValues = new ChartValues<MeasureModel>();
DataContext = this;
}
// 更新图表
private void Read()
{
PhaseChartValues.Add(new MeasureModel
{
Index = this.Index,
Value = this.PhaseValue
});
ModulusChartValues.Add(new MeasureModel
{
Index = this.Index,
Value = this.ModulusValue
});
// 限定图表最多只有十五个元素
if (PhaseChartValues.Count > 15)
{
PhaseChartValues.RemoveAt(0);
ModulusChartValues.RemoveAt(0);
}
}
}
}
窗体
在主窗体中插入上面写好的控件,并编写数据处理代码。
public partial class MainWindow : Window
{
private int index = 0;
public MainWindow()
{
InitializeComponent();
Task.Factory.StartNew(RecordData);
}
private void RecordData()
{
// 持续生成随机数,模拟数据处理过程
while (true)
{
Thread.Sleep(500);
var r = new Random();
float phase = r.Next(1, 7);
float modulus = r.Next(1, 10);
// 更新图表数据
constantChangesChart.PhaseValue = phase;
constantChangesChart.ModulusValue = modulus;
constantChangesChart.Index = index++;
}
}
}
实现效果
最终实现的效果:
下图是官网动态折线图示例中给的效果图,但是跟其网页里给的实际代码呈现效果完全不同,而且似乎有Bug。如果您知道如何实现,欢迎在评论中告知,十分感谢。
6 comments
为什么我在主窗口插入控件,不更新界面呀
我的也不更新
官网的图应该是每0.1秒秒移动一点,移动过程中如果出现新的点再加进去,这样才能看起来足够平滑。
缩放后怎么恢复动画?
用thread.sleep肯定不流畅
请教下,用什么会比较好呢