String aus einem anderen Thread in ein Formular einsetzen

  • VB.NET

Es gibt 22 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    String aus einem anderen Thread in ein Formular einsetzen

    Hallo Community,
    es geht mal wieder um Invoke und Delegate. Ich, als VB6 Umsteiger, verstehe den Zusammenhang von Invoke, Delegate und Thread leider noch nicht so richtig. Es gibt sehr viele Beiträge im Netz zu diesem Thema, aber die sind irgendwie doch jedes Mal etwas anders, was mich nur noch mehr verwirrt. Es muss doch irgendwo einen Beitrag geben, der für einen „Unwissenden“ verständlich macht, (gerne auch anhand von Beispielen) wann und wie Delegate und Invoke bei einem anderen Thread einzusetzen sind. Bevor ich nun zu meiner eigentlichen Frage komme, beschreibe ich erst einmal mein Projekt. Mein Projekt startet mit einem Formular, auf dem diverse Buttons und neben diesen jeweils ein Label angeordnet sind. Mit dem Button-Click Ereignis wird ein Telegramm über dem COM Port zu einem angeschlossenen Gerät gesendet. Um die Formular Klasse übersichtlicher zu halten, habe ich u.a. die DataReceived Sub in einem Module ausgelagert. Die empfangenen Daten, die ich in der DataReceive Sub auslese, sollen nun im Formular im Label neben dem jeweiligen Button angezeigt werden.
    1.) Wie bekomme ich die ausgelesenen Daten in eine Public Variable auf dem Formular, um sie in dem Label des jeweiligen Click Ereignisses einsetzen zu können?
    2.) Ist es Möglich, dass die DataReceived Sub auf ein Funktion umzustellen, die die zurückgelesenen Daten als Rückgabewert zurückgibt und wie müsste ich das dann machen?

    VB.NET-Quellcode

    1. Option Explicit On
    2. Option Strict On
    3. Imports System
    4. Imports System.IO.Ports
    5. Module Module1
    6. Public MySerialPort As New SerialPort
    7. Private comBuffer As Byte()
    8. Private Delegate Sub MyDelegate()
    9. Private MyDelegate1 As MyDelegate
    10. Public Sub MySerialPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
    11. MyDelegate1 = New MyDelegate(AddressOf Form1.EncodeReceivedData)
    12. Dim n As Integer = MySerialPort.BytesToRead
    13. comBuffer = New Byte(n - 1) {}
    14. MySerialPort.Read(comBuffer, 0, n)
    15. 'Aufruf der Delegate Routine
    16. MyDelegate1.Invoke(comBuffer) '<-- Zu viele Argumente für "Public Overridable Sub Invoke()"
    17. 'Schnittstelle schließen
    18. MySerialPort.Close()
    19. End Sub
    20. End Module
    @Famore Willkommen im Forum. :thumbup:
    Delegate ist im Prinzip eine Deklaration für eine Prozedur, die Du als Parameter verwenden kannst.
    Ein serielles Port stellt ein Event bereit, das ausgelöst wird, wenn Daten eingetroffen sind.
    Events sind Sub, nicht aber Function.
    Invoken musst Du, wenn Du Informationen zur Anzeige an der GUI aus einem Nebenthread in den GUI-Thread übertragen willst.
    Du kannst das SerialPort im Designer auf die GUI ziehen.
    Du kannst das SerialPort so behandeln, dass es Strings überträgt sollst, da musst Du nicht Bytes behandeln.

    VB.NET-Quellcode

    1. Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    2. Dim txt = SerialPort1.ReadExisting()
    3. Me.Invoke(Sub() Me.Label1.Text = txt)
    4. 'InvokeLabelTextChange(txt)
    5. End Sub
    6. Private Sub InvokeLabelTextChange(txt As String)
    7. If (Me.InvokeRequired) Then
    8. ' ruft sich selbst auf
    9. Me.Invoke(New Action(Of String)(AddressOf InvokeLabelTextChange), txt)
    10. Return
    11. End If
    12. Me.Label1.Text = txt
    13. End Sub
    Du hast hier zwei Möglichkeiten zum invoken: Als Einzeiler ("Lambda-Ausdruck) und als Prozeduraufruf (auskommentiert).
    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!

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

    Hallo RodFromGermany
    Vielen Dank für deine schnelle Antwort.
    Meine Frage Nr.2 ist damit beantwortet, bleibt also noch die Nr.1.
    Wenn ich dein Vorschlag richtig verstehe, werden alle Daten aus der SerialPort1_DataReceived Sub in das Label1 auf dem Formular geschrieben, egal welchen Button ich anklicke. Die SerialPort1_DataReceived Sub wäre dann auch wieder im Formular. Ich würde aber die Form1.vb der Übersicht wegen nicht gerne so „voll stopfen“ und habe deswegen unter anderen diese Sub in ein Module ausgelagert. Meine DataReceived Sub funktioniert bis Zeile 25, dort bekomme ich die Fehlermeldung, die als Kommentar hinter dem Invoke Aufruf steht.
    Vielleicht beschreibe ich mein Projekt noch einmal anders.
    Wenn ich auf meinem Formular z.B. auf Button1 klicke, wir eine Sub aufgerufen, die ein Telegramm über COM1 an ein Gerät sendet. Die Antwort - also die Daten der DataReveived Sub, die in einem anderen Thread (dem Modul1.vb)ist, sollen in dem Label1 auf dem Formular angezeigt werden. Wenn ich im Formular z.B. auf den Button2 klicke, sollen die Daten dann dementsprechend im Label2 des Formulars angezeigt werden usw..
    Dieses kann ich aber doch nur, wenn ich die Daten aus der DataReceived Sub in eine auf dem Formular mit Public deklarierten Variable setze. Danach kann ich im Click-Ereignis des Button1 mit
    Label1.Text = Variablenname
    den Inhalt der Variablen in Label1 auf dem Formular anzeigen lassen. Den gleichen Ablauf habe ich bei den anderen Buttons.
    Willkommen im Forum.

    Famore schrieb:

    Wenn ich auf meinem Formular z.B. auf Button1 klicke, wir eine Sub aufgerufen, die ein Telegramm über COM1 an ein Gerät sendet.

    Famore schrieb:

    Danach kann ich im Click-Ereignis des Button1 mit Label1.Text = Variablenname den Inhalt der Variablen in Label1 auf dem Formular anzeigen lassen.
    Meines Erachtens: Entweder, oder. Da die Antwort vom Gerät nebenläufig kommt, müsstest Du wohl im Click-EventHandler (EH) warten, bis die Antwort da ist, bevor Du dann das entsprechende Label beschriftest. Da wäre es wohl einfacher, wenn Du Dir in den Button-Click-EH* merkst, welcher Button geklickt wurde und dann im DataReceived-EH auswertest, welcher Button gedrückt wurde und das entsprechende Label beschriftest.

    * Man kann auch einen EH für alle Buttons erzeugen, indem am Ende des EH-Kopfes eben steht:

    VB.NET-Quellcode

    1. ... Handles Button1.Click, Button2.Click 'usw.
    und dann eben das sender-Objekt per DirectCast(sender, Button) umwandeln und merken.
    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.
    @Famore Das Modul weiß a priori nix von den Instanzen der beteiligten Formen, Du müsstest die betreffende Form oder ein Delegat reinreichen, damit dorthin invoked werden kann.
    Diese Herangehensweise halte ich für suboptimal.
    Gut ist es, in sich geschlosene Funktionalitäten in separate Klassen auszulagern, aber solch muss von anbeginn der Projektentwicklung geplant und implementiert werden.
    Dies nachträglich zu tun, ist meist ein erhebliocher Mehraufwand.
    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!
    Jo - seh ich auch so, und dieser Mehraufwand ist halt nu zu treiben.
    Nochmal dasselbe in meinen Worten erklärt:
    Im Modul gibt es genau einen SerialPort.
    Im Form gibts aber mehrere Buttons, die den scheints beschicken und seine Ergebnisse auswerten wollen.
    Das muss ja schon logisch ein schönes Durcheinander geben, wenn der eine Button den SP beschickt, der annere ihn aber auswerten will - oder wie soll das funzenudeln?

    Mein Vorschlag:
    Schaff das Modul ab und zieh stattdessen eine SerialPort-Komponente aufs Form.
    Ich glaube nämlich, dass ein auf Form gezogener SerialPort sich selbständig mit dem Form synchronisiert, sodass das Gehampel mit Control.Invoke sowieso entfallen kann.
    Aber kann ich nicht ausprobieren, müsstest du ausprobieren.

    Also fast wie in RFGs Post, nur ohne Invoking:

    VB.NET-Quellcode

    1. Imports System.IO.Ports
    2. '...
    3. Private _Txt As String = ""
    4. Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    5. Select Case e.EventType
    6. Case SerialData.Chars
    7. _Txt &= SerialPort1.ReadExisting()
    8. Case SerialData.Eof
    9. Label1.Text = _Txt
    10. _Txt = ""
    11. End Select
    12. End Sub
    (naja, und noch den EventType berücksichtigt, damit Beginn und Ende einer Sendung identifiziert werden - k.A., ob das so wirklich funzt.)

    Probierma!

    Das sind halt 10 Zeilen, die muss dein Form noch aushalten.
    Zumindest in dieser Form wäre es nicht sinnvoll, da iwas auszulagern, weil der Vorgang beginnt im Form, und muss auch wieder im Form enden - eine Auslagerei würde womöglich mehr Verwirrung stiften als Übersichtlichkeit schaffen.

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    Control.Invoke
    muss sein, denn das SerialPort arbeitet in einem NebenThread.
    Ich hab mit solch zu tun.
    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!
    Hallo zusammen
    Ich habe jetzt meine ausgelagert DataReceived Sub wieder in das Formular gebracht und sie nach dem Vorschlag von RodFromGermany abgewandelt. Wie bekomme ich aber jetzt die, aus der Schnittstelle gelesenen, Daten in das jeweilige Label? Da ich noch ein „Frischling“ in Sachen VB Programmierung bin, kann ich meine Probleme möglicherweise nicht so verständlich beschreiben und habe hier mal mein gekürztes Projekt. Ist leider immernoch sehr viel.

    @ ZaporiZed
    wie stelle ich das hier mit dem EventHandler an? Bei über 20 Buttons und RadioButtons wäre der EH ziemlich lang. Wie schon oben beschieben ist auf der Form neben jedem Button ein Label, in dem die DataReveived Daten zu sehen sein sollten.

    VB.NET-Quellcode

    1. Option Explicit On
    2. Option Strict On
    3. Imports System
    4. Imports System.IO.Ports
    5. Public Class Form1
    6. Private comBuffer As Byte()
    7. Dim RXD As String
    8. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    9. Dim SendeString As String = TxD(Convert.ToInt32("8", 16), _
    10. Convert.ToInt32("10", 16), _
    11. Convert.ToInt32("1", 16))
    12. Dim ChkSumm As Integer = CInt(Checksumme(SendeString))
    13. 'Das Telegramm an die Schnittstelle geben
    14. SendSerialData(SendeString & Chr(ChkSumm))
    15. '##############################################################################################
    16. ' hier habe ich gedacht, dass ich die Daten aus SerialPort1_DataReceived einsetzen kann.
    17. 'Die Antwort im Formular anzeigen
    18. Me.Label10.Text = RXD
    19. '#############################################################################################
    20. End Sub
    21. Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    22. Dim SendeString As String = TxD(Convert.ToInt32("8", 16), _
    23. Convert.ToInt32("23", 16), _
    24. Convert.ToInt32("0", 16))
    25. Dim ChkSumm As Integer = CInt(Checksumme(SendeString))
    26. 'Das Telegramm an die Schnittstelle geben
    27. SendSerialData(SendeString & Chr(ChkSumm))
    28. 'Die Antwort im Formular anzeigen
    29. Me.Label11.Text = RXD
    30. End Sub
    31. Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    32. Dim txt = SerialPort1.ReadExisting()
    33. Me.Invoke(Sub() Me.Label10.Text = txt)
    34. 'InvokeLabelTextChange(txt)
    35. 'Schnittstelle schließen
    36. SerialPort1.Close()
    37. End Sub
    38. Private Sub InvokeLabelTextChange(txt As String)
    39. If (Me.InvokeRequired) Then
    40. ' ruft sich selbst auf
    41. Me.Invoke(New Action(Of String)(AddressOf InvokeLabelTextChange), txt)
    42. Return
    43. End If
    44. Me.Label10.Text = txt
    45. End Sub
    46. Private Sub EncodeReceivedData()
    47. '###########################################################################
    48. 'hier habe ich gedacht, dass der Datenstring aus der Sub SerialPort1_DataReceived erst noch umgestellt
    49. 'und in die in dem Formular mit "Dim" deklarierten Variable "RXD" geschrieben werden könnte.
    50. 'Im Click-Ereignis des jeweiligen Buttons würde ich den Inhalt der Variablen in das jeweilige Label schreiben.
    51. '###########################################################################
    52. RXD = ""
    53. RXD = ("00" & Hex(CStr(comBuffer(0)))).Substring(("00" & Hex(CStr(comBuffer(0)))).Length - 2, 2) & " " & _
    54. ("00" & Hex(CStr(comBuffer(2)))).Substring(("00" & Hex(CStr(comBuffer(2)))).Length - 2, 2) & _
    55. ("00" & Hex(CStr(comBuffer(1)))).Substring(("00" & Hex(CStr(comBuffer(1)))).Length - 2, 2) & " " & _
    56. ("00" & Hex(CStr(comBuffer(4)))).Substring(("00" & Hex(CStr(comBuffer(4)))).Length - 2, 2) & _
    57. ("00" & Hex(CStr(comBuffer(3)))).Substring(("00" & Hex(CStr(comBuffer(3)))).Length - 2, 2) & " " & _
    58. ("00" & Hex(CStr(comBuffer(5)))).Substring(("00" & Hex(CStr(comBuffer(5)))).Length - 2, 2)
    59. End Sub

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Famore“ ()

    Definiere

    Famore schrieb:

    das jeweilige Label
    Was soll hier eigentlich rauskommen?

    VB.NET-Quellcode

    1. RXD = ("00" & Hex(CStr(comBuffer(0)))).Substring(("00" & Hex(CStr(comBuffer(0)))).Length - 2, 2) & " " & _
    2. ' ...
    Sieh Dir mal dies an:

    VB.NET-Quellcode

    1. Dim x = 1234
    2. MessageBox.Show(x.ToString("X8"))
    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!

    Famore schrieb:

    Bei über 20 Buttons und RadioButtons wäre der EH ziemlich lang.
    Ehm. Was für RadioButtons? Welche Funktion haben die? Sag mal bitte generell, was das GUI für einen Funktionalität grundsätzlich hat, denn 20 Buttons ... naja. Für Außenstehende erklärungsbedürftig. Find ich.
    Grundsätzlich geht es mit den EH so auch

    VB.NET-Quellcode

    1. Dim CurrentClickedButton As Button = Nothing
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. For Each Button In Me.Controls.OfType(Of Button)
    4. AddHandler Button.Click, AddressOf Button_Click
    5. Next
    6. End Sub
    7. Private Sub Button_Click(sender As Object, e As EventArgs)
    8. If CurrentClickedButton Is Nothing Then CurrentClickedButton = DirectCast(sender, Button)
    9. End Sub
    Ggf. könntest Du auch noch - wenn Du noch mehr Buttons hast, die nicht alle darauf reagieren sollen, bei Deinen Serial-Port-Buttons einen Eintrag in der Tag-Property hinterlegen und dann dieses auswertest, damit Du quasi aussortieren kannst, welche nicht auf den o.g. EventHandler reagieren sollen. Und dann, im DataReceived-Ereignis könntest Du dann per Invoke eine Sub aufrufen, in der dann CurrentClickedButton ausgewertet und das passende Label mit Text belegt wird. Und dann natürlich noch CurrentClickedButton wieder auf Nothing setzen, damit es für den nächsten Klick freigegeben ist. Man könnte auch ne Klick-Queue implementieren um dann schnelle Klicks auf verschiedene Buttons adäquat auswerten zu können, aber das kommt auch darauf an, wieviel Zeit vergeht, bis Dein COM-Port bzw. as Gerät die Daten zurückliefert, also antwortet.
    Aber: Zeile#56: SerialPort1.Close() Keine Ahnung wie das ist, aber ich dächt, dass @RodFromGermany mal schrieb, dass so ein Port bis zum Programmende am besten offen bleiben sollte. Aber ich will ihm da keine Aussagen nachsagen, die dann am Ende gar nicht stimmen. Und außerdem hab ich ja keine Ahnung von der Gesamtsituation vor Ort. Hat bestimmt seinen Sinn, den zu schließen.
    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.

    VaporiZed schrieb:

    dass so ein Port bis zum Programmende am besten offen bleiben sollte.
    So isses.
    Üblicherweise wechselt ja während der Programmlaufzeit das Gerät nicht.
    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!
    @RodFromGermany
    Jedem Button Steuerelement ist optisch ein Label Steuerelement zugeordnet.
    Beispiel: Auf meiner Form befindet sich der Button „Button1“. Rechts neben diesem Button ist das Label Steuerelement „Label1“ angeordnet. Dort sollte die Antwort auf die von Button1 gesendete Abfrage angezeigt werden. Der RXD String ist aus einem alten VB6 Projekt übernommen. Das zu sendende als auch das empfangene Telegramm von der seriellen Schnittstelle bestehen aus 6 Bytes (1 Control Byte, 2 Address Bytes, 2 Data Bytes und 1 Checksum Byte ) Little Endian. So stricke ich mir das Telegramm wieder in ein Format „00 0000 0000 00“ Big Endian. Das „x.ToString(„X8“) ist die elegantere und auch bessere Lösung. In meinem Fall müsste ich daraus dann ein „x.ToString(„X4“) machen. Das ist für mich als VB6 Umsteiger eine Verbesserung, wohingegen die Sache mit Delegate und Invoke aus meiner Sicht schwieriger geworden ist. In VB6 konnte man die Daten ganz einfach von einem Thread zum anderen schaffen.

    @VaporiZed
    Mit den Buttons werden verschiedene Daten aus einem am COM Port angeschlossenen Steuergerät ausgelesen oder hineingeschrieben und mit den RadioButtons setze ich verschiedene Ausgänge am Steuergerät auf High bzw. Low Pegel. Das zu sendende als auch das empfangene Telegramm von der seriellen Schnittstelle bestehen aus 6 Bytes (1 Control Byte, 2 Address Bytes, 2 Data Bytes und 1 Checksum Byte ) Little Endian. Deinen Vorschlag werde ich bei nächster Gelegenheit mal ausprobieren.

    @RodFromGermany und VaporiZed
    Den Port immer wieder zu öffnen und zu schließen war mein Gedanke eigentlich nur der Vermeidung eines Programmfehlers wegen unkontrollierten Datenaustausch an der Schnittstelle.

    Famore schrieb:

    Programmfehlers wegen unkontrollierten Datenaustausch an der Schnittstelle.
    Gibt es bei der RS232 nicht,
    Was Du brauchst ist eine Function SendCommandWait4Answer(cmd As String) As String.
    Je nach Antwortzeit kannst Du das synchron machen, also Kommando senden, warten und Antwort abholen.
    Die kannst Du dann direkt in des Buttons Label darstellen.
    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!
    @VaporiZed
    Der Vorschlag funktioniert, ist aber wegen den vielen Buttons mit sehr vielen Codezeilen verbunden. Die Label Zuweisung müsste ich ja dann mit Select Case geschehen. Aber abgesehen davon ist der Vorschlag super, vielen Dank.
    @RodFromGermany
    Ja, so habe ich mir das vorgestellt. Ich bekommen den ReadTimeout nicht zum feuern. Obwohl ich versuchsweise den SerialPort1.ReadTimeout = 10 gesetzt habe, wird kein ReadTimeout gefeuert wenn der Empfangspuffer leer bleibt. Damit ich aus der Do – Loop Schleife raus komme, habe ich mal einen Schleifenzähler eingesetzt. Dabei ist mir folgendes aufgefallen. Die Do–Loop Schleife läuft bei dem ersten klick auf eine Button einmal durch und hat dabei schon 6 Bytes aus dem Empfangspuffer ausgelesen. Bei jedem weitere klick auf einen der Buttons sind erst nach ca. 360 Do-Loop Schleifen die 6 Bytes im Empfangspuffer ausgelesen. Kann das so richtig sein oder liegt das an meinem Funktionsaufbau? Sorry, mir ist klar, dass er nicht NET Konform ist. Ist halt irgendwie funktionsmäßig nach VB6 Art zusammengebaut, da mir noch sehr viel NET Wissen und Praxis fehlt.

    VB.NET-Quellcode

    1. Function SendCommandWait4Answer(ByVal cmd As String) As String
    2. Dim strReceived As String = ""
    3. 'Wenn keine Daten zum Senden in Variable sind dann Sub verlassen
    4. If Len(cmd) = 0 Then
    5. Exit Function
    6. End If
    7. 'Sende Sendestring zur seriellen Schnittstelle
    8. Try
    9. SerialPort1.DiscardInBuffer()
    10. SerialPort1.Write(cmd)
    11. Dim i As Integer = 0
    12. Do
    13. If SerialPort1.BytesToRead > 5 Then strReceived = SerialPort1.ReadExisting
    14. i += 1
    15. Loop Until strReceived.Length = 6 Or i = 2000
    16. MessageBox.Show(i & " Schleifen und " & strReceived.Length & " Zeichen gelesen")
    17. Catch ex As Exception
    18. MessageBox.Show(ex.Message)
    19. Return "-1"
    20. End Try
    21. Return strReceived
    22. End Function

    Famore schrieb:

    Bei jedem weitere klick auf einen der Buttons sind erst nach ca. 360 Do-Loop Schleifen die 6 Bytes im Empfangspuffer ausgelesen. Kann das so richtig sein oder liegt das an meinem Funktionsaufbau?
    Dein Gerät wird wohl nicht so schnell antworten können wie die Do-Schleife sich wiederholt.

    Famore schrieb:

    Die Label Zuweisung müsste ich ja dann mit Select Case geschehen.
    oder mit der Tag-Property, wie oben erwähnt. Aber so oder so ist es erstmal viel (einmalige) Schreibarbeit. Alternativ: Ein UserControl aus Button und Label erstellen. Dann wird's deutlich übersichtlicher und einfacher.

    Famore schrieb:

    Sorry, mir ist klar, dass er nicht NET Konform ist.

    Dann wohl besser die empfohlenen VS-Einstellungen verwenden.
    Damit Du auch weißt, wo es noch hinkt:

    Option Strict On aktivieren. (OSO)
    Zeile#2: Nothing statt "", da Strings nicht variabel sind und so eine spätere Zuweisung (Z#18) zu neuen String-Instanzen führt. Für Dich nicht relevant, aber erwähnenswert.
    Z#5: cmd.Length nutzen, da Len VB6 ist
    Z#7: OSO -> Function gibt hier keinen Wert zurück
    Z#10, #25 ff.: Fange nur Exceptions ab, die Du kennst und sinnvoll bearbeiten kannst.
    Z#21: OrElse statt Or (analog: AndAlso statt And)
    Z#23: OSO -> i und strReceived.Length (? da verwendest Du es ja statt Len) sind Integer und für die MessageBox erstmal nicht verarbeitbar.

    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.

    Famore schrieb:

    SerialPort1.ReadTimeout = 10
    10 Millisekunden?
    Zieh doch mal den Stecker raus, sofern es sich um die RS232 handelt, da kommt gewiss ein TimeOut.
    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!
    @VaporiZed
    “Option Explicit On” und “Option Strict On” sind bei mir immer im Projekt aktiviert. In Zeile 5 bin ich dann wohl wieder in die VB6 Syntax gefallen. Deinen Bericht über die Exceptions habe ich zur Kenntnis genommen und versuche es zu befolgen. Vielen Dank für die Empfehlungen zu meine Function.
    @RodFromGermany
    Ja, es handelt sich um eine RS232. Das habe ich schon versucht. Es wird irgendwie kein TimeOut gefeuert. Ich weis momentan nicht wo der Fehler liegen könnte.
    @Famore Ein Timeout kommt dann, wenn Du synchron Daten lesen willst, aber keine Daten zur Verfügung stehen. Möglicherweise sollte auch das DataReceived-Event nicht aboniert sein, aber da bin ich mir nicht sicher.
    Poste mal den relevanten Code,
    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!

    Neu

    Hallo RodFromGermany
    Ich habe in der “SendCommandWait4Answer” Funktion (s.o.) auch schon versuchsweise die Zeile 25 gegen Catch ex As TimeoutException ausgetauscht. War aber auch nicht erfolgreich.
    Ich habe noch eine eher allgemeine Frage. Diese Art über den seriellen Port zu kommunizieren ähnelt stark dem, was ich von VB6 her kenne. Wenn man im Internet nach „.Net“ und „serialport“ sucht, bekommt man nur Beispiele mit Delegate und Invoke, so als ob es keine andere Möglichkeit der Port Kommunikation geben würde. Ist die Art ohne Delegate und Invoke über den Port zu kommunizieren nur noch wegen der Kompatibilität zu alten VB Projekten möglich oder warum sind nur Beispiele mit Delegate und Invoke zu finden?

    Hier ist meine kompette Port Einstellung

    VB.NET-Quellcode

    1. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    2. 'Alle verfügbaren Ports ermitteln und mit dem Portnamen in KomboBox ablegen
    3. Call GetSerialPortName()
    4. With SerialPort1
    5. .PortName = CStr(Me.cmbPorts.Text)
    6. .BaudRate = CInt("9600")
    7. .DataBits = CInt("8")
    8. .Parity = IO.Ports.Parity.None
    9. .StopBits = IO.Ports.StopBits.One
    10. 'Sonstige Port Einstellungen
    11. .Encoding = System.Text.Encoding.Default
    12. .ReadTimeout = 10 'nur zu Testzwecken auf 10msec gestellt.
    13. End With
    14. SerialPort1.Open()
    15. End Sub

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

    Neu

    Famore schrieb:

    Ist die Art ohne Delegate und Invoke über den Port zu kommunizieren nur noch wegen der Kompatibilität zu alten VB Projekten möglich oder warum sind nur Beispiele mit Delegate und Invoke zu finden?
    Das mit Delegate und Invoke stellt Nebenläufigkeit bereit - (übrigens auf eine veraltete Art - evtl. wären Techniken aus dem Task-Umfeld eleganter).

    Nebenläufigkeit ist sicher schön und bei Kommunikation mit SerialPorts bestimmt in den meisten Fällen erwünscht.
    Aber deswegen ist eine Kommunikation ohne Nebenläufigkeit natürlich nicht veraltet.

    Es sind halt zwei Dinge: Nebenläufigkeit und Kommunikation.

    Und nebenläufige Kommunikation ist eben dieselbe Kommunikation, die du auch verwendest, nur eben noch das Nebenläufigkeits-Feature hinzugefügt.

    Also dadurch, dass es Eis mit Sahne gibt, ist Eis an sich (also ohne Sahne) ja nicht obsolet.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()