2016-12-01 68 views
1

我使用活動圖表將數據記錄到傳入的串行數據。從長遠來看,我將從Arduino發送6組不同的變量。從U-Z標記。我的圖表只是在讀取和繪製數據時以相對較好的速度工作,但只要「if」語句涉及,它的速度就會大大降低。我擔心的是,一旦我整合了另外6個數據(雖然每個圖只有2個,因此總共有3個圖),但程序運行速度太慢以至於無法記錄數據。「活動圖表」圖表刷新速度隨着數據處理和添加到圖表而減緩WPF c#

我已經添加了一個文本框來讀取所有傳入的數據,並且正在按預期進行更新。除此之外,隨着更多數據添加到該圖中,該圖似乎也會減慢,即使我在本質上「脫離屏幕」時刪除了點。

謝謝!

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; } 
} 
+0

在網站https://lvcharts.net/App/examples/v1/wpf/Performance%20Tips –

回答

1

這是艱難的沒有得到的代碼分析器,看看那裏的主要掐尖是說。這裏有幾個thigns嘗試

  • 使用ELSE-IF模式假設StrIncomingSerial字符串只有一個類型的值,每讀
  • 您正試圖解析字符串到一個號碼,然後再次將其轉換,嘗試使用的Num您以前使用
  • 您似乎在每個時鐘週期的呼喚SetAxisLimits兩次,嘗試刪除這些

一個讓我知道這是否有助於

+0

有一個性能提示文章嗨凱文,感謝回覆抱歉,我一直在玩的延遲迴複用這個ALOT。我提出了你的建議(減去3號,因爲我找不到第二個?)。 奇怪的是,如果我完全刪除了if語句並且有一組數據,那麼它就可以正常工作(不得不說還不是很棒),但是一旦我實現了「如果read line是Z,解析並繪製.. 。)它似乎凍結了,但是我的串行流的文本框沒有,並且仍然全速運行。我一直在使用這個代碼與Zgraphs工作令人驚訝地從Windows窗體移動一個程序! – charley

+0

我已經有有機會和你的代碼稍微玩一下,並且可以通過在圖表控件中添加DisableAnimations =「True」來讓它工作得很好。至於第3點,你在第110和175行調用它。 –

+0

您需要將列表中的「Trimming」添加到「ChartValuesTwo」列表中。說到這一點,在您的XAML中,您稱之爲ChartValues2,因此您需要更正該列表。 –

1

閱讀:

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

如果您使用這些屬性,你可以得到更多的速度:

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

的attibute 'DataTooltip' 的影響很大。

+0

雖然這可能會回答這個問題,但 [這將是更可取的](http://meta.stackoverflow.com/q/8259)在這裏包含更多的 答案的基本部分,並提供供參考的鏈接。 – Peter