WPF 图表控件LiveCharts的应用——室内监控可视化

需求

为了实现一个完整软件系统,必须具备一些基本的数据呈现控件,例如曲线图、柱状图、饼图等。本次的业务需求为:利用LiveCharts展示后台模拟的温度变化。像Winform里面,微软为我们提供了比较完整的Chart控件,但是在WPF组件中,就没有找到类似的控件,它的意图是让我们自己去实现。我们应该对当下的代码共享时代环抱感激,迄今位置有很多面向WPF的第三方控件库,大部分都是免费开源的。例如:OxyPlot、ModernuiCharts......以及我们今天的主角——LiveCharts。这是一个具备动画效果的图表控件。

首先上效果:

 

环境

Windows 10

Visual Studio 2019

.Net Framework 4.7.2

Ninject

LiveCharts

LiveCharts.Wpf

 

实现

1.通过NuGet引入Ninject、LiveCharts.Wpf、LiveCharts程序包。

解决方案资源管理器-->项目(右键)-->管理NuGet程序包

在“浏览”中搜索:

Ninject

LiveCharts

LiveCharts.Wpf

并安装,完成之后如下图所示:

WPF 图表控件LiveCharts的应用——室内监控可视化_第1张图片

 

2.在XAML中引用LiveCharts控件的程序集。

在ChamberView.xaml文件的节点上添加对程序集的应用,如下:

其中 xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"就是命名空间的引用。

3.使用LiveCharts控件,值用绑定的方式传递到界面。

                    
                        
                            
                        
                        
                            
                                
                                    
                                
                            
                        
                        
                            
                        
                    

如上所示,我们这里有一些属性是通过绑定来赋值的。因此接下来我们来完善这块工作。

4.数据绑定与刷新

4.1定义一个数据点结构——MeasureModel

    /// 
    /// 测量模型
    /// 
    public class MeasureModel
    {
        /// 
        /// X 轴数据
        /// 
        public DateTime DateTime { get; set; }

        /// 
        /// Y 轴数据
        /// 
        public double Value { get; set; }
    }

4.2定义界面相关的视图模型ViewModel

定义通知属性、普通属性和命令以及构造时初始化等工作。

using Deamon.Util.DI;
using LiveCharts;
using LiveCharts.Configurations;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Deamon.ViewModel
{    
    /// 
    /// 房间信息
    /// 
    public class ChamberViewModel : BaseViewModel
    {
        /// 
        /// 默认构造函数
        /// 
        public ChamberViewModel()
        {
            // 初始化创建一个 X Y 轴上数据显示的图表,并确定 X Y 轴的数据结构
            var mapper = Mappers.Xy()
              .X(model => model.DateTime.Ticks) 
              .Y(model => model.Value);

            // 配置这个图表,可以被其他地方(特定的方式)使用
            Charting.For(mapper);

            // 初始化测量的数据集
            ChartValues = new ChartValues();

            // 设置 X 轴显示的标签格式
            DateTimeFormatter = value => new DateTime((long)value).ToString("mm:ss");

            // 设置图表的其他相关属性
            AxisStep = TimeSpan.FromSeconds(1).Ticks;
            AxisUnit = TimeSpan.TicksPerSecond;

            SetAxisLimits(DateTime.Now);

            // 默认情况下开始数据刷新
            IsReading = false;
            this.InjectStopOnClick();
        }

        #region 公共命令

        /// 
        /// 显示导航栏命令
        /// 
        public RelayCommand ShowBarCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    IoC.Get().HasNavigationBar = true;
                });
            }
        }

        /// 
        /// 显示导航栏命令
        /// 
        public RelayCommand ReadingCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    this.InjectStopOnClick();
                    RaisePropertyChanged(nameof(ReadingCommandText));
                });
            }
        }

        #endregion

        #region 属性

        /// 
        /// 缓存的测量数据
        /// 
        public ChartValues ChartValues { get; set; }

        /// 
        /// 时间格式化器
        /// 
        public Func DateTimeFormatter { get; set; }

        /// 
        /// X 轴上每个数据的等距跳变(时)长
        /// 
        public double AxisStep { get; set; }
        public double AxisUnit { get; set; }

        /// 
        /// 正在读取
        /// 
        public bool IsReading { get; set; }

        /// 
        /// 控制按钮的文本
        /// 
        public string ReadingCommandText
        {
            get
            {
                return IsReading ? "Stop" : "Start";
            }
        }

        private string curvalue;

        /// 
        /// 当前值
        /// 
        public string Curvalue
        {
            get { return curvalue; }
            set
            {
                curvalue = value;
                RaisePropertyChanged(nameof(Curvalue));
            }
        }

        private double axisMax;

        /// 
        /// X轴最大
        /// 
        public double AxisMax
        {
            get { return axisMax; }
            set
            {
                axisMax = value;
                RaisePropertyChanged(nameof(AxisMax));
            }
        }

        private double axisMin;

        /// 
        /// X轴最小
        /// 
        public double AxisMin
        {
            get { return axisMin; }
            set
            {
                axisMin = value;
                RaisePropertyChanged(nameof(AxisMin));
            }
        }

        #endregion

        /// 
        /// 模拟数据采集
        /// 
        public void Read()
        {
            while (IsReading)
            {
                Thread.Sleep(400);
                var now = DateTime.Now;
                double value = Math.Round(new Random().Next(10, 11) + (1 * new Random().NextDouble()), 2);
                ChartValues.Add(new MeasureModel
                {
                    DateTime = now,
                    Value = value
                });
                SetAxisLimits(now);
                Curvalue = value + "℃";
                // 只保留160个数据,满了就把前面的数据移除
                if (ChartValues.Count > 160) ChartValues.RemoveAt(0);
            }
            IsReading = false;
        }

        /// 
        /// 设置 X 轴上呈现的时间范围
        /// 
        /// 
        private void SetAxisLimits(DateTime now)
        {
            // X轴显示区域的最大时间
            AxisMax = now.Ticks + TimeSpan.FromSeconds(1).Ticks;
            // X轴显示区域的最大时间
            AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; 
        }

        /// 
        /// 根据标识是否启动采集
        /// 
        public void InjectStopOnClick()
        {
            IsReading = !IsReading;
            if (IsReading)
            {
                Task.Factory.StartNew(Read);
            }
        }

    }
}

4.3数据绑定和界面完善


    
        
            
            
        

        
            

 

Over

每次记录一小步...点点滴滴人生路...

你可能感兴趣的:(C#,WPF)