使用Livecharts Constant Changes示例根据时间绘制点,以及从串口读取数据?

时间:2017-05-01 22:58:25

标签: c# wpf xaml linegraph livecharts

好的,所以基本上我想让这个图取代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; }
}

1 个答案:

答案 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>