Forum: PC-Programmierung Visual C# SerialPort Event Handler


von Jan H. (janiiix3)


Lesenswert?

Nabend,

ich möchte gerne auf Eingehende Bytes reagieren und diese speichern.
Die Messagebox erscheint zwar mit den ankommenden Daten, dass Programm 
hängt sich aber auf sobald es den Eingehenden String in die TextBox 
schreiben soll.

Wie kann ich das umgehen?
1
        void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
2
        {
3
            SerialPort localPort = (SerialPort)sender;
4
            uartInput = localPort.ReadExisting();
5
            saveReceivedData(this,uartInput);
6
        }
7
8
        void saveReceivedData(object sender, string input)
9
        {
10
            MessageBox.Show(input);
11
            this.uartMessageBox.Text = input;
12
        }

von Felix U. (ubfx)


Lesenswert?

Unwahrscheinlich, dass das am Textfeld liegt. Hast du vielleicht 
irgendwo im Main/UI Thread eine Schleife mit einem blockierenden Aufruf? 
Was sagt der Debugger wo das Programm "hängt"?

von Jan H. (janiiix3)


Lesenswert?

Es hat glaube ich was mit nem Thread zu tun? Der Eventhandler arbeitet 
doch extra, unabhänging von der ursprünglichen Form oder?

Muss man da nicht irgendwie mit "invoke" oder so arbeiten?

von Peter II (Gast)


Lesenswert?

Jan H. schrieb:
> dass Programm
> hängt sich aber auf sobald es den Eingehenden String in die TextBox
> schreiben soll.

was heist es hängt sich auf? drücke "Pause" und schau dann wo der 
Programm steht.

von Felix U. (ubfx)


Lesenswert?

Könnte sein, dass die MessageBox den Thread zu lange blockiert. 
Kommentiere die Messagebox mal aus.

von STK500-Besitzer (Gast)


Lesenswert?

Felix U. schrieb:
> Könnte sein, dass die MessageBox den Thread zu lange blockiert.
> Kommentiere die Messagebox mal aus.

Das sollte sie eben nicht, da sie ja auf keine Antwort wartet.
Ansonsten den Empfangsstring per delegate in eine Listbox oder so 
eintragen.

von dunno.. (Gast)


Lesenswert?

Vermutlich läuft die empfangsroutine nicht im ui context.

Die messagebox ist Aber ui context, das funktioniert so nicht.

Dispatcher.invoke ist das zauberwort.

https://stackoverflow.com/questions/1644079/change-wpf-controls-from-a-non-main-thread-using-dispatcher-invoke

von bluppdidupp (Gast)


Lesenswert?

dunno.. schrieb:
> Vermutlich läuft die empfangsroutine nicht im ui context.

Genau - so ist es.

DataReceived der SerialPort-Klasse wird in einem eigenen Thread 
aufgerufen, nicht im typischen UI-Thread.
Windows-Forms Controls müssen aber in der Regel aus dem Thread heraus 
aktualisiert werden, von dem aus sie auch erstellt wurden. Dafür haben 
die betreffenen Controls ein InvokeRequired-Property um mitzuteilen, ob 
Invoke nötig ist.

Versucht man trotzdem vom falschen Thread aus zu updaten wird häufig 
eine Exception ausgelöst, die Frickler gerne via 
CheckForIllegalCrossThreadCalls=false einfach deaktivieren, statt kurz 
zu recherchieren was es damit auf sich hat ;D

von Jan H. (janiiix3)


Lesenswert?

dunno.. schrieb:
> Vermutlich läuft die empfangsroutine nicht im ui context.
>
> Die messagebox ist Aber ui context, das funktioniert so nicht.
>
> Dispatcher.invoke ist das zauberwort.
>
> 
https://stackoverflow.com/questions/1644079/change-wpf-controls-from-a-non-main-thread-using-dispatcher-invoke

Okay. Wie wende ich das jetzt konkret auf meine Funktion an? Bin noch 
ziemlich unerfahren. Kannst du mir das mal anhand meines Problems 
schildern?
Da wäre ich dir endlos dankbar.

von bluppdidupp (Gast)


Lesenswert?

Eine kompakte Variante wäre:
1
void saveReceivedData(object sender, string input)
2
{
3
    this.uartMessageBox.Invoke(() => {
4
       MessageBox.Show(input);
5
       this.uartMessageBox.Text = input;
6
    });
7
}
...durch das Invoke() wird quasi für den angegebenen Code auf den Thread 
zu dem uartMessageBox gehört gewechselt und dort der Code ausgeführt.
(siehe auch: https://stackoverflow.com/a/253150/3408300)

In deiner
1
void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
würde ich außerdem noch e.EventType abfragen, siehe dazu das potentielle 
Deadlock-Problem mit EoF hier: 
https://stackoverflow.com/a/13438355/3408300

von Jan H. (janiiix3)


Angehängte Dateien:

Lesenswert?

bluppdidupp schrieb:
> Eine kompakte Variante wäre:
>
1
> void saveReceivedData(object sender, string input)
2
> {
3
>     this.uartMessageBox.Invoke(() => {
4
>        MessageBox.Show(input);
5
>        this.uartMessageBox.Text = input;
6
>     });
7
> }
8
>
> ...durch das Invoke() wird quasi für den angegebenen Code auf den Thread
> zu dem uartMessageBox gehört gewechselt und dort der Code ausgeführt.
> (siehe auch: https://stackoverflow.com/a/253150/3408300)
>
> In deiner
1
void DataReceivedHandler(object sender, 
2
> SerialDataReceivedEventArgs e)
> würde ich außerdem noch e.EventType abfragen, siehe dazu das potentielle
> Deadlock-Problem mit EoF hier:
> https://stackoverflow.com/a/13438355/3408300


Danke erstmal für die Erklärung.
Leider klappt das nicht? Er sagt mir folgendes.. (siehe Bild)

von Sebastian E. (sbe_15)


Lesenswert?

Besser wäre:
1
this.uartMessageBox.BeginInvoke(...);
Bei Invoke könnte der Backgroundthread blockieren bis die Messagebox vom 
User "verarbeitet" wird.

Zu deinem Fehler:
Lambda-Expressions funktionieren tatsächlich nicht immer als Parameter.
In https://stackoverflow.com/a/253150/3408300 stehen aber genug 
Alternativen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.