前端部分:
<UserControl x:Class="MvvmProjectFrame.Views.RealTimeView"
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:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MvvmProjectFrame.Views" d:DataContext="{d:DesignInstance Type=local:RealTimeView}"
mc:Ignorable="d"
d:DesignHeight="930" d:DesignWidth="1770">
<UserControl.Resources>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="Width" Value="80"/>
<Setter Property="Margin" Value="10,0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border BorderThickness="0,0,0,2" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}">
<ContentPresenter Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontSize" Value="16"/>
<Setter Property="Background" Value="#FFE6EDEB"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="FontSize" Value="16"/>
<Setter Property="Background" Value="#ffD1E5FB"/>
<Setter Property="BorderBrush" Value="#B6BC0B"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
<TextBlock Text="选择显示曲线:" FontSize="14" VerticalAlignment="Center" Margin="5,0"/>
<ComboBox x:Name="comboBoxName1" Margin="10,0" FontSize="14" Width="150" Height="25"/>
<Button Content="开始" Click="Button_Click" Style="{StaticResource buttonStyle}"/>
<Button Content="停止" Click="Button_Click_1" Style="{StaticResource buttonStyle}"/>
<Button Content="实时曲线" Click="Button_Click_2" Style="{StaticResource buttonStyle}"/>
<Button Content="历史曲线" Click="Button_Click_3" Style="{StaticResource buttonStyle}"/>
<Button Content="查询" Click="Button_Click_4" Style="{StaticResource buttonStyle}"/>
<TextBox x:Name="dateTimeBox3" Text="2023-04-06 15:18:30" VerticalAlignment="Center" Margin="5,0,0,0" Width="180" Background="White"/>
<TextBox Text="至" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10,5,5,5" Background="Transparent" Foreground="Black" BorderBrush="White" BorderThickness="0"/>
<TextBox x:Name="dateTimeBox4" Text="2023-04-06 15:19:30" VerticalAlignment="Center" Margin="5,0,10,0" Width="180" Background="White"/>
<TextBlock Text="当前曲线名称:" FontSize="14" VerticalAlignment="Center"/>
<TextBlock x:Name="liveChartName" Text="{Binding ElementName=comboBoxName1, Path=Text}" Margin="10,0,0,0" Width="100" FontSize="14" VerticalAlignment="Center"/>
</StackPanel>
<lvc:CartesianChart Grid.Row="1" AnimationsSpeed="0:0:0.5" Zoom="{Binding iZoom}" Pan="{Binding iPan}">
<lvc:CartesianChart.Series>
<lvc:LineSeries Values="{Binding ChartValues}"
PointGeometry="{x:Null}"
Fill="Transparent"
StrokeThickness="2"
Stroke="Red"
LineSmoothness="1"/>
</lvc:CartesianChart.Series>
<lvc:CartesianChart.AxisX>
<lvc:Axis LabelFormatter="{Binding DateTimeFormatter}"
MaxValue="{Binding AxisMax}"
MinValue="{Binding AxisMin}"
Unit="{Binding AxisUnit}"
Foreground="Black">
<lvc:Axis.Separator>
<lvc:Separator Step="{Binding AxisStep}"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis MinValue="0" MaxValue="{Binding Ymax}" Foreground="Black">
<lvc:Axis.Separator>
<lvc:Separator Step="{Binding YStep}" />
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
</Grid>
</UserControl>
后端部分:
using LiveCharts;
using LiveCharts.Configurations;
using MvvmProjectFrame.Models;
using Prism.Mvvm;
using System;
using System.ComponentModel;
using System.Data.SQLite;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace MvvmProjectFrame.Views
{
/// <summary>
/// RealTimeView.xaml 的交互逻辑
/// </summary>
public partial class RealTimeView : UserControl,INotifyPropertyChanged
{
public ChartValues<MeasureModel> ChartValues { get; set; }
public Func<double, string> DateTimeFormatter { get; set; }
SqliteConnection sqlite = new SqliteConnection();
//实现接口通知
public event PropertyChangedEventHandler PropertyChanged;
public void Changed(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//X轴显示数据最小个数和最大个数
private double _axisMax;
public double AxisMax
{
get { return _axisMax; }
set { _axisMax = value; Changed("AxisMax"); }
}
private double _axisMin;
public double AxisMin
{
get { return _axisMin; }
set { _axisMin = value; Changed("AxisMin"); }
}
//轴步骤单元
public double AxisStep { get; set; }
public double AxisUnit { get; set; }
//Y轴显示数据最大数和间隔
private double _yMax;
public double Ymax
{
get { return _yMax; }
set { _yMax = value; Changed("Ymax"); }
}
private double _yStep;
public double YStep
{
get { return _yStep; }
set { _yStep = value; Changed("YStep"); }
}
//曲线数值
public double curveValue { get; set; }
//曲线启停控制
public bool liveChartStart { get; set; }
//存储时间
public DateTime dateTimeData { get; set; }
//实时曲线和历史曲线切换
public bool curveMode { get; set; } = false;
//表名称
public string _chartName { get; set; } = "实时曲线";
//放大平移功能
private string _izoom = "None";
public string iZoom
{
get { return _izoom; }
set { _izoom = value; Changed("iZoom"); }
}
private string _ipan = "None";
public string iPan
{
get { return _ipan; }
set { _ipan = value; Changed("iPan"); }
}
public RealTimeView()
{
InitializeComponent();
try
{
//使用DateTime.Ticks作为X,将value属性用作Y
var mapper = Mappers.Xy<MeasureModel>()
.X(model => model.DateTime.Ticks)
.Y(model => model.Value);
//全局保存映射器。
Charting.For<MeasureModel>(mapper);
//values属性将存储我们的值数组
ChartValues = new ChartValues<MeasureModel>();
//设置如何显示X标签
DateTimeFormatter = value => new DateTime((long)value).ToString("HH:mm:ss");
//AxisStep强制X轴上每个分隔符之间的距离
AxisStep = TimeSpan.FromSeconds(1).Ticks;
//AxisUnit力让轴知道我们正在绘制秒
//这并不总是必要的,但它可以防止错误的标签
AxisUnit = TimeSpan.TicksPerSecond;
}
catch (Exception)
{
return;
}
this.comboBoxName1.Items.Add("一次供水温度");
this.comboBoxName1.Items.Add("一次回水温度");
this.comboBoxName1.Items.Add("二次供水温度");
this.comboBoxName1.Items.Add("二次回水温度");
this.comboBoxName1.Items.Add("一次供水压力");
this.comboBoxName1.Items.Add("一次回水压力");
this.comboBoxName1.Items.Add("二次供水压力");
this.comboBoxName1.Items.Add("二次回水压力");
this.comboBoxName1.SelectedIndex = 0;
liveChartStart = true;
try
{
//绑定数据上下文
DataContext = this;
Task.Run(async () =>
{
await Read();
});
}
catch (Exception)
{
return;
}
}
//开始
private void Button_Click(object sender, RoutedEventArgs e)
{
liveChartStart = true;
}
//停止
private void Button_Click_1(object sender, RoutedEventArgs e)
{
liveChartStart = false;
}
//实时曲线
private void Button_Click_2(object sender, RoutedEventArgs e)
{
curveMode = false;
liveChartStart = true;
_chartName = "实时曲线";
ChartValues.Clear();
liveYmax(this.comboBoxName1);
//iZoom = "None";
//iPan = "None";
}
//历史曲线
private void Button_Click_3(object sender, RoutedEventArgs e)
{
curveMode = true;
liveChartStart = false;
ChartValues.Clear();
_chartName = "历史曲线";
//iZoom = "X";
//iPan = "Unset";
}
//查询
private void Button_Click_4(object sender, RoutedEventArgs e)
{
if (_chartName == "历史曲线")
{
SqliteData(sqlite, "./data.db", "datatask", dateTimeBox3.Text, dateTimeBox4.Text, this.comboBoxName1.Text);
}
}
/// <summary>
/// 连接数据库对应显示曲线
/// </summary>
/// <param name="dbpath">数据库地址</param>
/// <param name="tableName">表名称</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <param name="lineName">曲线名称</param>
private void SqliteData(SqliteConnection sqlite, string dbpath, string tableName, string startTime, string endTime, string lineName)
{
try
{
//建立数据块连接
sqlite.SqliteConnOpen(dbpath);
//全部查询数据,返回一个数据流
SQLiteDataReader reader = sqlite.QueryCriteria(tableName, "Time", startTime, endTime);
//判断曲线名称,reader循环执行下一条返回true,直至没有下一条返回false;
switch (lineName)
{
case "一次供水温度":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Temp1", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 150, 25);
}
break;
case "一次回水温度":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Temp2", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 150, 25);
}
break;
case "二次供水温度":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Temp3", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 150, 25);
}
break;
case "二次回水温度":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Temp4", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 150, 25);
}
break;
case "一次供水压力":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Pressure1", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 16, 2);
}
break;
case "一次回水压力":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Pressure2", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 16, 2);
}
break;
case "二次供水压力":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Pressure3", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 16, 2);
}
break;
case "二次回水压力":
if (reader != null)
{
while (reader.Read())
{
SetAddData(reader, "Pressure4", "DateTime");
}
//获取当前时间,设置X轴长度限制
SetAxisProperties(dateTimeData, 30, 0, 16, 2);
}
break;
}
sqlite.SqliteConnClose();
}
catch (Exception)
{
return;
}
}
private async Task Read()
{
while (true)
{
if (liveChartStart)
{
await Task.Delay(250);
this.Dispatcher.Invoke(() =>
{
if (curveMode == false)
{
liveYmax(this.comboBoxName1);
ChartValues.Add(new MeasureModel
{
DateTime = DateTime.Now,
Value = curveValue
});
//只使用最后150个值
if (ChartValues.Count > 150) ChartValues.RemoveAt(0);
}
});
}
}
}
/// <summary>
/// 根据不同曲线名称,设置Y轴最大值、间距,随机数范围
/// </summary>
/// <param name="comboBox"></param>
public void liveYmax(ComboBox comboBox)
{
try
{
switch (comboBox.Text)
{
case "一次供水温度":
case "一次回水温度":
case "二次供水温度":
case "二次回水温度":
SetAxisProperties(DateTime.Now, 1, 8, 150, 25);
curveValue = MeasureModel.TempValue;
break;
case "一次供水压力":
case "一次回水压力":
case "二次供水压力":
case "二次回水压力":
SetAxisProperties(DateTime.Now, 1, 8, 32, 2);
curveValue = MeasureModel.TempValue;
break;
}
}
catch (Exception)
{
return;
}
}
/// <summary>
/// 设置X/Y轴属性
/// </summary>
/// <param name="now">当前时间</param>
/// <param name="minSeconds">x轴最小秒数</param>
/// <param name="maxSeconds">x轴最大秒数</param>
/// <param name="ymax">y轴最大值</param>
/// <param name="ystep">y轴间距</param>
private void SetAxisProperties(DateTime now, int minSeconds, int maxSeconds, double ymax, double ystep)
{
try
{
//让我们强制轴 落后8秒
AxisMax = now.Ticks + TimeSpan.FromSeconds(minSeconds).Ticks; // lets force the axis to be 1 second ahead
AxisMin = now.Ticks - TimeSpan.FromSeconds(maxSeconds).Ticks; // and 8 seconds behind
Ymax = ymax;
YStep = ystep;
}
catch (Exception)
{
return;
}
}
/// <summary>
/// 添加数据
/// </summary>
/// <param name="reader">数据流</param>
/// <param name="name">数据库里的名称</param>
/// <param name="dateTime">数据库里的时间</param>
private void SetAddData(SQLiteDataReader reader, string name, string dateTime)
{
curveValue = Convert.ToDouble(reader[name]);
dateTimeData = Convert.ToDateTime(reader[dateTime]);
this.Dispatcher.Invoke(() =>
{
ChartValues.Add(new MeasureModel
{
DateTime = dateTimeData,
Value = curveValue
});
});
}
}
}