好的,所以基本上我想让这个图取代DateTime并根据秒表绘制X轴。然后我希望来自串口的数据在Y轴上绘制数据。只需按一下按钮,就可以实现这一切。
以下是我遵循的示例:
https://lvcharts.net/App/examples/v1/wpf/Constant%20Changes
它的问题在于它使用系统时间而不是某种秒表。我正在使用WPF,并希望扩展此图的功能。
如果有人可以通过Skype或其他方式帮助我。请让我知道!
最终,我希望能够从图表中获取所有数据并将其保存在某处。所以我可以稍后比较以前的观点。
谢谢!
Mainwindow.cs.xaml
<Window x:Class="TestChartProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestChartProject"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Click="InjectStopOnClick">
Inject/Stop Data
</Button>
<!--Here we disable tooltips and hovering to get a better performance-->
<lvc:CartesianChart Grid.Row="1" AnimationsSpeed="0:0:1" Hoverable="True" DataTooltip="{x:Null}">
<lvc:CartesianChart.Series>
<lvc:LineSeries Values="{Binding ChartValues}"
PointGeometry="{x:Null}"
LineSmoothness="1"
StrokeThickness="6"
Stroke="#F34336"
Fill="Transparent"/>
</lvc:CartesianChart.Series>
<lvc:CartesianChart.AxisX>
<lvc:Axis LabelFormatter="{Binding DateTimeFormatter}"
MaxValue="{Binding AxisMax}"
MinValue="{Binding AxisMin}"
Unit="{Binding AxisUnit}">
<lvc:Axis.Separator>
<lvc:Separator Step="{Binding AxisStep}" />
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
MainWindow.cs
private double _axisMax;
private double _axisMin;
private double _trend;
public MainWindow()
{
InitializeComponent();
//To handle live data easily, in this case we built a specialized type
//the MeasureModel class, it only contains 2 properties
//DateTime and Value
//We need to configure LiveCharts to handle MeasureModel class
//The next code configures MeasureModel globally, this means
//that LiveCharts learns to plot MeasureModel and will use this config every time
//a IChartValues instance uses this type.
//this code ideally should only run once
//you can configure series in many ways, learn more at
//http://lvcharts.net/App/examples/v1/wpf/Types%20and%20Configuration
var mapper = Mappers.Xy<MeasureModel>()
.X(model => model.Session.Ticks) //use DateTime.Ticks as X
.Y(model => model.Value); //use the value property as Y
//lets save the mapper globally.
Charting.For<MeasureModel>(mapper);
//the values property will store our values array
ChartValues = new ChartValues<MeasureModel>();
//lets set how to display the X Labels
DateTimeFormatter = value => new DateTime((long)value).ToString("mm:ss");
//AxisStep forces the distance between each separator in the X axis
AxisStep = TimeSpan.FromSeconds(1).Ticks;
//AxisUnit forces lets the axis know that we are plotting seconds
//this is not always necessary, but it can prevent wrong labeling
AxisUnit = TimeSpan.TicksPerSecond;
SetAxisLimits(DateTime.Now);
//The next code simulates data changes every 300 ms
IsReading = false;
DataContext = this;
}
public ChartValues<MeasureModel> ChartValues { get; set; }
public Func<double, string> DateTimeFormatter { get; set; }
public double AxisStep { get; set; }
public double AxisUnit { get; set; }
public double AxisMax
{
get { return _axisMax; }
set
{
_axisMax = value;
OnPropertyChanged("AxisMax");
}
}
public double AxisMin
{
get { return _axisMin; }
set
{
_axisMin = value;
OnPropertyChanged("AxisMin");
}
}
public bool IsReading { get; set; }
private void Read()
{
var r = new Random();
while (IsReading)
{
Thread.Sleep(1);
var now = DateTime.Now;
_trend = r.Next(100);
ChartValues.Add(new MeasureModel
{
Session = now,
Value = _trend
});
SetAxisLimits(now);
//lets only use the last 150 values
if (ChartValues.Count > 10) ChartValues.RemoveAt(0);
}
}
private void SetAxisLimits(DateTime now)
{
AxisMax = now.Ticks + TimeSpan.FromSeconds(1).Ticks; // lets force the axis to be 1 second ahead
AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; // and 8 seconds behind
}
private void InjectStopOnClick(object sender, RoutedEventArgs e)
{
IsReading = !IsReading;
if (IsReading) Task.Factory.StartNew(Read);
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
MeasureModel
public class MeasureModel
{
public DateTime Session { get; set; }
public double Value { get; set; }
}
答案 0 :(得分:1)
基于我认为你需要的东西,也许这会对你有所帮助:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//used to generate random values
var r = new Random();
var t = 0d;
//lets instead plot elapsed milliseconds and value
var mapper = Mappers.Xy<MeasureModel>()
.X(x => x.ElapsedMilliseconds)
.Y(x => x.Value);
//save the mapper globally
Charting.For<MeasureModel>(mapper);
Values = new ChartValues<MeasureModel>();
var sw = new Stopwatch();
sw.Start();
Task.Run(() =>
{
while (true)
{
Thread.Sleep(500);
//we add the lecture based on our StopWatch instance
Values.Add(new MeasureModel
{
ElapsedMilliseconds = sw.ElapsedMilliseconds,
Value = t += r.Next(0,10)
});
}
});
DataContext = this;
}
public ChartValues<MeasureModel> Values { get; set; }
}
public class MeasureModel
{
public double ElapsedMilliseconds { get; set; }
public double Value { get; set; }
}
XAML:
<lvc:CartesianChart>
<lvc:CartesianChart.Series>
<lvc:LineSeries Values="{Binding Values}" />
</lvc:CartesianChart.Series>
</lvc:CartesianChart>