Chart-Control Datenbindung

  • VB.NET

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von JoachimStein.

    Chart-Control Datenbindung

    Hallo VB Gemeinde,

    zunächst einmal vielen Dank an alle die hier fleißig posten um zu helfen. Das hat mir bisher immer viel geholfen, doch jetzt bin ich an einem Punkt, an dem ich auch mal eine Frage habe.

    Kurz zu mir: Ich bin Joe, 44 Jahre alt. Vor gut acht Jahren habe ich mit Bierbrauen im Keller angefangen. Da ich beruflich in der Automatisierungsbranche tätig bin hab ich sofort angefangen, zeitintensive Prozesse zu automatisieren. Da ich vom Programmieren keine Ahnung habe/hatte, begann ich mit MS Access und VBA eine Steuerung über serielle Schnittstelle zu basten. Das ganze ist aber nun an seine Grenzen gestoßen und ich bin nun auf VB umgestiegen. Alle meine Programmierkenntnisse in VB habe ich von VBA adaptiert und aus diversen Foren, vor allem von vb-paradise.

    Nun zur meiner Frage:
    Ich habe die serielle Kommunikation in eine DLL gepackt um von der GUI unabhängig zu sein. Ich habe unter anderem eine List-Objekt geschaffen (Code siehe unten), welches die Daten aufbereitet und als

    Public ReadOnly Property DataSeries As New Charting.Series() (Zeile 15)

    bereitstellt. Neue hinzugefügte Werte werden dann mit
    DataSeries.Points.AddXY(objSampledValue.TimeStamp, objSampledValue.Value) (Zeile 77)

    in die „DataSeries“ aufgenommen. Das klappt soweit wie gewünscht. Wenn ich jetzt in einer Forms-Anwendung die „DataSeries“ einer „Series“-Auflistung eines „Chart-Controls“ hinzufüge, wird das Diagramm entsprechend angezeigt und aktualisiert.
    crtSensor1.Series.Add(objSensor.MeasuredValues.DataSeries)
    crtSensor1.Series.Add(objSensor.MovingAverages.DataSeries)


    Mein Problem ist, das beim Schließen des Fensters mit dem Diagramm, die „Points-Auflistung“ der „DataSeries“ auf „Nothing“ gesetzt wird und natürlich eine "Exception" auslöst. Das ist nicht erwünscht. Da die Werte erhalten bleiben sollen.

    Ich habe gesehen, das es noch weitere Möglichkeiten wie z.B. „DataBindings“ gibt, Daten an ein „Chart-Control“ zu binden.
    Welche Methode der Datenbindung würdet Ihr für meine Situation empfehlen?

    Danke an alle die Antworten bereits im Voraus.
    Gruß
    JOE

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports BrewMaticCore
    2. Imports System.Windows.Forms.DataVisualization
    3. Public Class ValueList
    4. Inherits List(Of Value)
    5. Private Const intSamplingRateMilliseconds As Integer = 500
    6. Private datNextSample As Date
    7. Public ReadOnly Property DataSeries As New Charting.Series()
    8. Private Sub Quantize()
    9. Dim objLastValue As SensorValue = Nothing
    10. Dim objCurrentValue As SensorValue = Last
    11. Dim objSampledValue As SensorValue = Nothing
    12. If Count = 1 Then
    13. Dim intFirstSampleMillisecond As Integer = Math.Round((objCurrentValue.TimeStamp.Millisecond / intSamplingRateMilliseconds) + 0.5, 0) * intSamplingRateMilliseconds
    14. If intFirstSampleMillisecond = 1000 Then
    15. intFirstSampleMillisecond = 0
    16. End If
    17. datNextSample = objCurrentValue.TimeStamp.AddMilliseconds(intFirstSampleMillisecond - objCurrentValue.TimeStamp.Millisecond)
    18. ElseIf Count >= 2 Then
    19. objLastValue = Item(Count - 2)
    20. End If
    21. If objCurrentValue.TimeStamp > datNextSample Then
    22. objSampledValue = objCurrentValue
    23. If Not IsNothing(objLastValue) Then
    24. If objLastValue.TimeStamp >= datNextSample Then
    25. objSampledValue = objLastValue
    26. Else
    27. Dim intNextSampleMillisecond As Integer = IIf(datNextSample.Millisecond = 0, 1000, datNextSample.Millisecond)
    28. Dim intLastValueMillisecond As Integer = IIf(objLastValue.TimeStamp.Millisecond = 0, 1000, objLastValue.TimeStamp.Millisecond)
    29. Dim intCurrentValueMillisecond As Integer = IIf(objCurrentValue.TimeStamp.Millisecond = 0, 1000, objCurrentValue.TimeStamp.Millisecond)
    30. If Math.Abs(intNextSampleMillisecond - intLastValueMillisecond) < Math.Abs(intCurrentValueMillisecond - intNextSampleMillisecond) Then
    31. objSampledValue = objLastValue
    32. End If
    33. End If
    34. End If
    35. objSampledValue.TimeStamp = datNextSample
    36. DataSeries.Points.AddXY(objSampledValue.TimeStamp, objSampledValue.Value)
    37. datNextSample = datNextSample.AddMilliseconds(intSamplingRateMilliseconds)
    38. End If
    39. End Sub
    40. Public Shadows Sub Add(Item As Value)
    41. MyBase.Add(Item)
    42. Quantize()
    43. End Sub
    44. Public Sub New()
    45. DataSeries.ChartType = Charting.SeriesChartType.Line
    46. DataSeries.XValueType = Charting.ChartValueType.Time
    47. End Sub
    48. End Class

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „JoachimStein“ ()

    Willkommen im Forum. :thumbup:

    JoachimStein schrieb:

    um von der GUI unabhängig zu sein
    Wenn Du Chart-spezifische Daten bereitstellst, ist das sehrwohl GUI-abhängig.
    Besswe wäre es, wenn Du eine List(Of Integer) (bzw. Dein Datentyp) bereitstellst.
    Die GUI holt dann die Daten ab und bereitet sie für sich auf.
    ====
    Was bei Dir im Einzelnen passiert, kann ich nicht sagen, da ist zu wenig Code da.
    Wahrscheinlich wird beim Schließen des Fensters die DLL-SerialPort-Instanz gelöscht, womit dann die Daten weg wären, das ist aber nur eine Vermutung.
    Richte das ganze so ein, dass das SerialPort während der ganzen Laufzeit des Programms geöffnet ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Danke für die Rückmeldung.

    Die SerialPort-Instanzen laufen munter weiter, nachdem das Fenster geschlossen wird/wurde. Erst nachdem ein neues "DataReceived"-Event auslöst, kommt es zu der "Exception" in Zeile 77 (DataSeries.Points.AddXY(objSampledValue.TimeStamp, objSampledValue.Value)

    Hier noch der Code aus dem Test-Formular:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports BrewMaticCom
    2. Imports BrewMaticCore
    3. Public Class frmDeviceClass_AG245
    4. Private objDevice As Device_AG245
    5. Private Sub SetControlState()
    6. cmdConnect.Enabled = Not IsNothing(objDevice) AndAlso objDevice.ConnectionActivities.Standby
    7. cmdDisconnect.Enabled = Not IsNothing(objDevice) AndAlso (objDevice.DeviceStates.Connected And Not objDevice.ConnectionActivities.Disconnecting)
    8. cmdInitialize.Enabled = Not IsNothing(objDevice) AndAlso (objDevice.DeviceStates.Connected And Not objDevice.ConnectionActivities.Disconnecting)
    9. cmdTara.Enabled = Not IsNothing(objDevice) AndAlso (objDevice.DeviceStates.Connected And Not objDevice.ConnectionActivities.Disconnecting)
    10. cmdWeight.Enabled = Not IsNothing(objDevice) AndAlso (objDevice.DeviceStates.Connected And Not objDevice.ConnectionActivities.Disconnecting)
    11. cmdSendImmediatelyRepeat.Enabled = Not IsNothing(objDevice) AndAlso (objDevice.DeviceStates.Connected And Not objDevice.ConnectionActivities.Disconnecting)
    12. cmdZero.Enabled = Not IsNothing(objDevice) AndAlso (objDevice.DeviceStates.Connected And Not objDevice.ConnectionActivities.Disconnecting)
    13. End Sub
    14. Private Sub frmDeviceClass_AG245_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    15. objDevice = frmDevices.SelectedDevice
    16. Dim objSensor = objDevice.Sensors.Item(0)
    17. SetControlState()
    18. txtModel.Text = objDevice.DeviceClass.Model
    19. txtSerialnumber.Text = objDevice.Serialnumber
    20. txtName.Text = objSensor.Name
    21. txtPin.Text = objSensor.Pin
    22. txtRangeMax.Text = objSensor.Range.MaximumValue
    23. txtRangeMin.Text = objSensor.Range.MinimumValue
    24. AddHandler objDevice.DeviceStates.StatusChanged, AddressOf SetControlState
    25. AddHandler objDevice.ConnectionActivities.StatusChanged, AddressOf SetControlState
    26. AddHandler objDevice.Sensors.Item(0).NewValue, AddressOf NewValueHandler
    27. crtSensor1.Series.Add(objSensor.MeasuredValues.DataSeries)
    28. crtSensor1.Series.Add(objSensor.MovingAverages.DataSeries)
    29. End Sub
    30. Private Sub NewValueHandler(sender As Object, e As EventArgs)
    31. Dim objSensor As Sensor = DirectCast(sender, Sensor)
    32. txtAnswer.Text = objSensor.MeasuredValue.TimeStamp & " | " & objSensor.MeasuredValue.Value
    33. txtMessage.Text = objSensor.MeasuredValue.Message
    34. txtValue.Text = objSensor.MeasuredValue.ValueUnit
    35. txtValueP.Text = objSensor.MeasuredValuePercent.ValueUnit
    36. txtStDevValue.Text = objSensor.StandardDeviationValue.ValueUnit
    37. txtMovAvg.Text = objSensor.MovingAverage.ValueUnit
    38. txtMovAvgP.Text = objSensor.MovingAveragePercent.ValueUnit
    39. txtStDevMovAvg.Text = objSensor.StandardDeviationMovingAverage.ValueUnit
    40. txtGradient.Text = objSensor.Gradient.ValueUnit
    41. End Sub
    42. Private Sub cmdInitialize_Click(sender As Object, e As EventArgs) Handles cmdInitialize.Click
    43. objDevice.CommandReset()
    44. End Sub
    45. Private Sub cmdTara_Click(sender As Object, e As EventArgs) Handles cmdTara.Click
    46. objDevice.CommandTara()
    47. End Sub
    48. Private Sub cmdWeight_Click(sender As Object, e As EventArgs) Handles cmdWeight.Click
    49. objDevice.CommandSendImmediately()
    50. End Sub
    51. Private Sub cmdSendImmediatelyRepeat_Click(sender As Object, e As EventArgs) Handles cmdSendImmediatelyRepeat.Click
    52. objDevice.CommandSendImmediatelyRepeat()
    53. End Sub
    54. Private Sub cmdConnect_Click(sender As Object, e As EventArgs) Handles cmdConnect.Click
    55. objDevice.Connect()
    56. End Sub
    57. Private Sub cmdDisconnect_Click(sender As Object, e As EventArgs) Handles cmdDisconnect.Click
    58. objDevice.Disconnect()
    59. End Sub
    60. Private Sub cmdZiro_Click(sender As Object, e As EventArgs) Handles cmdZero.Click
    61. objDevice.CommandZero()
    62. End Sub
    63. End Class

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „JoachimStein“ ()

    JoachimStein schrieb:

    kommt es zu der "Exception"
    Wie ist denn der genaue Text der Exception?
    ====
    Wwenn Du wieder mal einen längeren Code posteast, mach nen drum herum, am besten, Du editierst beide Posts von Dir.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Morgen früh werde ich die Hardware nochmal anschmeissen und die genaue Exception posten.
    Das mit dem Spoiler werde ich dann auch anpassen. Danke für den Tip.

    Aber jetzt steht erstmal Fußball auf dem Plan.

    JoachimStein schrieb:

    Erst nachdem ein neues "DataReceived"-Event auslöst, kommt es zu der "Exception" in Zeile 77
    Wenn Du das Form schließt, dann melde doch einfach per RemoveHandler die Events ab, die Du vorher per AddHandler hinzugefügt hast. Man kann natürlich vor der fehlererzeugenden Zeile auch prüfen, ob DataSeries und Points Nothing sind und dann die Sub abbrechen, aber die Eventabmeldung erscheint mit sauberer.

    btw: IsNothing() ist doch aus'm Microsoft.VisualBasic-Namespace. Schau mal ggf. bei den Empfohlenen Einstellungen vorbei.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Guten Morgen,

    also DataSeries.Points auf Nothing zu prüfen um die Exception zu vermeiden ist schonmal eine gute Sache. Wichtig ist aber, das Points nicht auf Nothing gesetzt wird, da damit alle Messwerte verloren gehen. Für dieses Problem habe ich eine Lösung gefunden. Im Closing-Event des Formular habe ich crtSensor1.Series.Clear eingefügt. Damit lässt sich das Fenster schließen, ohne das die Exeption ausgelöst wird.

    Des weitern habe ich mal die Variante von RodFromGermany mit einer List (of ...) versucht. Diese Variante scheint mir in meinem Fall, mit meinen Kenntnissen zu umständlich. Daher habe ich mich derzeit dazu entschieden auf das Chart-Control zu verzichten und das Diagram in einer Picture-Box zeichnen zu lassen. Hier hat mir sehr das Oszilloskop-Beispiel von RodFromGermany geholfen.

    Nochmals vielen Dank für Eure Hilfe, Tips und Zeit.