c# - "Live Charts"图形刷新速度随着数据的处理和添加到 WPF C# 图表而变慢

标签 c# wpf visual-studio livecharts

我使用实时图表来记录传入的串行数据。从长远来看,我将从 Arduino 发送 6 组不同的变量。从 U-Z 标记。当我的图表只是读取和绘制数据时,它以相对较好的速度工作,但是一旦涉及“if”语句,它就会大大减慢。我担心的是,一旦我合并了另外 6 条数据(尽管每个图只有 2 条,所以总共有 3 张图),程序将运行得太慢,以至于不值得记录数据。

我已经添加了一个文本框来读取所有传入的数据,并且正在按预期进行更新。此外,随着向其添加更多数据,图表似乎也变慢了,即使我在点基本上“离开屏幕”后删除了它们。

谢谢!

public partial class MainWindow : Window, INotifyPropertyChanged
{

    private double _axisMax;
    private double _axisMin;
    Stopwatch stopwatch = new Stopwatch();
    SerialPort myPort;

    public MainWindow()
    {
        InitializeComponent();

        myPort = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
        myPort.Open();
        //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 ChartValues instance uses this type.
        //this code ideally should only run once, when application starts is reccomended.
        //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.DateTime.Ticks)   //use DateTime.Ticks as X
            .Y(model => model.Value);           //use the value property as Y

        var mapper2 = Mappers.Xy<Graph1SecondVal>()
            .X(model => model.DateTime.Ticks)   //use DateTime.Ticks as X
            .Y(model => model.Value);

        //lets save the mapper globally.
        Charting.For<MeasureModel>(mapper);
        Charting.For<Graph1SecondVal>(mapper2);


        //the values property will store our values array
        ChartValues = new ChartValues<MeasureModel>();
        ChartValuesTwo = new ChartValues<Graph1SecondVal>();

        //lets set how to display the X Labels
        DateTimeFormatter = value => new DateTime((long)value).ToString("hh:mm:ss");

        AxisStep = TimeSpan.FromSeconds(1).Ticks;
        SetAxisLimits(DateTime.Now);

        //The next code simulates data changes every 300 ms
        Timer = new DispatcherTimer
        {
            Interval = TimeSpan.FromMilliseconds(10)
        };
        Timer.Tick += TimerOnTick;
        IsDataInjectionRunning = false;
        R = new Random();
        DataContext = this;
    }
    public ChartValues<Graph1SecondVal> ChartValuesTwo { get; set; }
    public ChartValues<MeasureModel> ChartValues { get; set; }
    public Func<double, string> DateTimeFormatter { get; set; }

    public double AxisStep { 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 DispatcherTimer Timer { get; set; }
    public bool IsDataInjectionRunning { get; set; }
    public Random R { get; set; }

    private void RunDataOnClick(object sender, RoutedEventArgs e)
    {
        if (IsDataInjectionRunning)
        {
            stopwatch.Stop();
            Timer.Stop();
            IsDataInjectionRunning = false;
        }
        else
        {
            stopwatch.Start();
            Timer.Start();


            IsDataInjectionRunning = true;
        }
    }

    private void TimerOnTick(object sender, EventArgs eventArgs) // Class is referencing from here!
    {
        var now = DateTime.Now;
        ProcessData();
        SetAxisLimits(DateTime.Now);
        //lets only use the last 30 values
        if (ChartValues.Count > 50) ChartValues.RemoveAt(0);
    }

    private void SetAxisLimits(DateTime now)
    {
        AxisMax = now.Ticks + TimeSpan.FromSeconds(1).Ticks; // lets force the axis to be 100ms ahead
        AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; //we only care about the last 8 seconds
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        if (PropertyChanged != null) // if subrscribed to event
            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    void ProcessData()
    {
        int NumberInt = 0;
        string IncomingSerial = myPort.ReadLine(); // Read incomming serial data
        string StrIncomingSerial = IncomingSerial.ToString(); // convert this data to workable string

        if (StrIncomingSerial.Contains("Z"))
        {
                string Number = myPort.ReadLine(); // Read Serialport
                double Num; // Create variable "Num"
                bool isNum = double.TryParse(Number, out Num); // Is the incomming serial data a number?
                if (isNum) // If it is a number...
                {
                    NumberInt = Convert.ToInt16(Number); // convert string to int
                    textBox1.Text = NumberInt.ToString() + "," + textBox1.Text;

            }

            myPort.DiscardInBuffer();
            ChartValues.Add(new MeasureModel
            {
                DateTime = DateTime.Now,
                Value = NumberInt

            });
        }

        if (StrIncomingSerial.Contains("Y"))
        {
                string Number = myPort.ReadLine(); // Read Serialport
                double Num; // Create variable "Num"
                bool isNum = double.TryParse(Number, out Num); // Is the incomming serial data a number?
                if (isNum) // If it is a number...
                {
                    NumberInt = Convert.ToInt16(Number); // convert string to int
                    textBox1.Text = NumberInt.ToString() + "," + textBox1.Text;
                }

            myPort.DiscardInBuffer();
            ChartValuesTwo.Add(new Graph1SecondVal
            {
                DateTime = DateTime.Now,
                Value = NumberInt
            });
        }

        SetAxisLimits(DateTime.Now);

    }

    private void ReadSerial_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 0; i < 10; i++)
        {
            string Number = myPort.ReadLine(); // Read Serialport
            textBox1.Text = Number.ToString() + "," + textBox1.Text;
        }

        myPort.DiscardInBuffer();

    }
}

<Window
    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:graph_test_6"
    xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
    xmlns:geared="clr-namespace:LiveCharts.Geared;assembly=LiveCharts.Geared"
    xmlns:chart="http://mindfusion.eu/charting/wpf" x:Class="graph_test_6.MainWindow"
    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" Height="30" Click="RunDataOnClick">
        Inject/Stop Data
    </Button>
    <lvc:CartesianChart Grid.Row="1" AnimationsSpeed="0:0:0" Hoverable="False">
        <lvc:CartesianChart.Series>
            <lvc:LineSeries Values="{Binding ChartValues}" PointGeometrySize="5" StrokeThickness="1" />
            <lvc:LineSeries Values="{Binding ChartValues2}" PointGeometrySize="5" StrokeThickness="1" />
        </lvc:CartesianChart.Series>
        <lvc:CartesianChart.AxisX>
            <lvc:Axis LabelFormatter="{Binding DateTimeFormatter}" 
                      MaxValue="{Binding AxisMax}" 
                      MinValue="{Binding AxisMin}"
                      DisableAnimations="True">
                <lvc:Axis.Separator>
                    <lvc:Separator Step="{Binding AxisStep}"></lvc:Separator>
                </lvc:Axis.Separator>
            </lvc:Axis>
        </lvc:CartesianChart.AxisX>
    </lvc:CartesianChart>
    <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="323,-71,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
    <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="189" Margin="43,299,0,-199" Grid.Row="1" TextWrapping="Wrap" Text="0" VerticalAlignment="Top" Width="203"/>
    <Button x:Name="ReadSerial" Content="Button" HorizontalAlignment="Left" Height="54" Margin="43,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="ReadSerial_Click"/>
</Grid>

    public class MeasureModel
{
    public DateTime DateTime { get; set; }
    public double Value { get; set; }
}



    public class Graph1SecondVal
{
    public DateTime DateTime { get; set; }
    public double Value { get; set; }
}

最佳答案

读这个:

https://lvcharts.net/App/examples/v1/wpf/Performance%20Tips

如果你使用这些属性,你可以获得更快的速度:

<lvc:CartesianChart Hoverable="False" DataTooltip="{x:Null}" />

属性'DataTooltip'影响很大。

关于c# - "Live Charts"图形刷新速度随着数据的处理和添加到 WPF C# 图表而变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40906201/

相关文章:

c# - 在 if 语句中设置变量,然后告诉它未分配

c# - 如何在不使用 EF 的情况下连接到 ASP.NET Core Web API 中的数据库?

c# - 在 C# 接口(interface)应用程序之间通信并注入(inject)到另一个进程 dll

wpf - 在文本框上过滤 DataGrid

sql - 将 SQL Server Express 数据库导出到 .SDF 文件(本地数据库)

asp.net - 错误: allowDefinition ='MachineToApplication' beyond application level

c# - Entity Framework 数据库连接问题

c# - 实现 INotifyPropertyChanged - 是否存在更好的方法?

c# - 为什么这个用户控件扩展中的所有对象在运行时都是空的?

visual-studio - 版本控制 "in the clouds"