前言

现目需要在软件界面上实时显示数据的变化,实现类似心电图的效果,发现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>

参数1参数2参数3

其中曲线部分参数:

  • Values:绑定C\#代码中的实际数据值 。
  • PointGeometry:数据点的外观。{x:Null}即不标出,只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 CircleCrossDiamondSquareTriangle可选。
  • 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。如果您知道如何实现,欢迎在评论中告知,十分感谢。
官网效果

如果觉得我的文章对你有用,请随意赞赏