Forum: PC-Programmierung C# WPF serielle Schnittstelle Problem mit Thread


von Daniel M. (daniel_91)


Angehängte Dateien:

Lesenswert?

Hallo zusammen.

Ich habe ein kleines Programm in C# (WPF) geschrieben, welches aus einem 
Hauptfenster und einem untergeordneten Fenster besteht (dieses wird über 
einen Button aus dem Hauptfenster heraus geöffnet).

In diesem untergeorneten Fenster wird ein Objekt der Klasse "SerialPort" 
instanziert und im Konstruktor des Fensters die serielle Schnittstelle 
geöffnet und ein Event auf den Empfang eines Bytes auf dieses Objekt 
aboniert.

Im dem Eventhandler (wenn Daten empfangen wurden) wird anschließend über 
eine TextBox eine Ausgabe in dem untergeorneten Fenster gemacht ("Daten 
empfangen").

Das klappt auch alles wunderbar, allerdings nur bei ersten Öffnen des 
untergeorneten Fensters. Wenn ich dieses schließe und danach wieder (aus 
dem Hauptfenster heraus) öffne, wird über die TextBox nur noch zufällig 
beim Empfang von einem Byte eine Ausgabe getätigt. Schließe ich die 
ganze Anwendung und starte sie neu, funktioniert alles wieder wie 
erwartet. Aber nur solange ich das untergeordnete Fenster nicht schließe 
und wieder öffne.

Ich kann mir beim besten Willen nicht erklären, woher dieses Verhalten 
herkommt.
Kann es sein, dass der Thread, der die serielle Schnittstelle ausliest, 
bei Schließen des untergeordneten Fensters nicht mit beendet wird und es 
dann beim erneuten Start dieses Fernsters zu Problemen führt?

Im Anhang habe ich mal das Programm gepackt. Ich hoffe Ihr könnt mir 
helfen. Vielen Dank im Vorraus.

von AmanitaMuscaria (Gast)


Lesenswert?

1
private void ButtonBeendenClick(object eventSender, RoutedEventArgs eventData)
2
{
3
  if (serialPort.IsOpen)
4
  {
5
    serialPort.Close();
6
  }
7
  this.Close();
8
}

Und wenn das Fenster anders geschlossen wird?
1
private void OnClosed(object sender, CancelEventArgs e)
2
{
3
  serialPort.DataReceived -= SerialPortDataReceived;
4
5
  if(serialPort.IsOpen) serialPort.Close();
6
}

*******************
1
private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
2
{
3
  // Empfangene Daten aufbereiten und in diesem Fenster ausgeben
4
  Dispatcher.Invoke(new Action(() =>
5
  {
6
    // Wenn 1 Byte empfangen wurde, wird etwas im Fenster geändert
7
    if (serialPort.BytesToRead == 1)
8
9
    ...

Warum gehst du davon aus, dass genau 1 Byte empfangen wird (==1)? Der 
Handler wird nicht für jedes einzelne Byte aufgerufen. Und bei Invoke 
kann es einen Deadlock geben, wenn du den Port schließen willst.
1
Dispatcher.BeginInvoke(new Action(() =>
2
{
3
  ...

*******************
1
// Hintergrund weiß färben
2
textBox1.Background = Brushes.White;
3
// Text löschen
4
textBox1.Text = "";
5
6
...
7
8
// Hintergrund grün färben
9
textBox1.Background = Brushes.Lime;
10
// Text ausgeben
11
textBox1.Text = "Daten Empfangen";
12
// Empfangspuffer löschen
13
serialPort.DiscardInBuffer();
14
15
...
16
17
// Serielle Schnittstelle schließen, falls diese offen ist
18
if (serialPort.IsOpen)
19
{
20
  serialPort.Close();
21
}
22
// Fenster schliesen
23
this.Close();

99% der Kommentare in deinem Code sind nicht nur überflüssig, sondern 
verschlechtern die Lesbarkeit ...

SerialPort und die Kommunikation gehören nicht in eine Fensterklasse. 
Verwende zumindest eine eigene Klasse und z.B. Events (über die dein 
Fenster aufbereitete Daten zur Darstellung erhält).

von Daniel M. (daniel_91)


Lesenswert?

Danke für die Antwort.

Das mit dem Kündigen des Events habe ich vergessen. Mit dieser Änderung 
geht es aber jetzt.

AmanitaMuscaria schrieb:
> 99% der Kommentare in deinem Code sind nicht nur überflüssig, sondern
> verschlechtern die Lesbarkeit ...

Das sehe ich anders. Im Programmcode werden Kommentare ja grün 
dargestellt und heben sich somit vom Funktionscode deutlich ab. Zudem 
gibt es im Code meiner Meinung nach keine überflüssigen Kommentare. Für 
jemanden, der gerade mit C# anfängt, sind auch solche Kommentare ggf. 
sehr hilfreich.

: Bearbeitet durch User
von Rainer V. (rudi994)


Lesenswert?

Daniel M. schrieb:
> gibt es im Code meiner Meinung nach keine überflüssigen Kommentare. Für
> jemanden, der gerade mit C# anfängt, sind auch solche Kommentare ggf.
> sehr hilfreich.

Für Anfänger richtig, solange es zweckmässig und nicht übertrieben ist. 
Nach etwas Routine im Programmieren werden auch die Kommentare weniger. 
Falsch ist, unzureichende oder gar keine Kommentare zu schreiben, weil 
man nach Jahren den eigenen Code nicht mehr versteht. Dann war die Mühe 
beim Schreiben von seitenweise Quellcode reine Zeitverschwendung.

Manchmal sind Kommenatre aber völlig überflüssig, wie hier:
printf("Stackpointer=%x\n",iSPTR); //Leckeres Pilz-Omelett: 5 Eier,
printf("Datensegment=%x\n",iDSEG); //2 Fliegenpilze, 300g Mehl

von AmanitaMuscaria (Gast)


Lesenswert?

Daniel M. schrieb:
> Das mit dem Kündigen des Events habe ich vergessen. Mit dieser Änderung
> geht es aber jetzt.

Gut, freut mich. Manchmal hängt man bei solchen Dingen ewig fest. Ich 
würde aber empfehlen, auch die anderen Sachen zu ändern, falls du es 
noch nicht gemacht hast:

Aufräumen in OnClosed des zweiten Fensters: Der Button ist ja nicht die 
einzige Art, das Fenster zu schließen; verwendet man die "falsche", gibt 
es Probleme, weil der entsprechende Code nicht ausgeführt wird.

BeginInvoke statt Invoke, da sonst unter ungünstigen Umständen im 
Zusammenspiel mit SerialPort dein Programm einfriert. Die Hintergründe 
sind etwas kompliziert, aber wie gesagt, es kann zu einem Deadlock 
kommen.

Wenn das Programm umfangreicher werden sollte, könnte man SerialPort und 
die ganze Kommunikation aus dem Fenster herausnehmen. Puristen würden 
vermutlich anmerken, dass so etwas "nie" direkt in den Code der 
Fensterklasse bzw. überhaupt die GUI gehört, aber bei einem kleinen 
Programm muss man meiner Meinung nach nicht päpstlicher als der Papst 
sein.

> Für jemanden, der gerade mit C# anfängt, sind auch solche Kommentare ggf.
> sehr hilfreich.

Ja, ein Anfänger mag ein paar Kommentare mehr schreiben bzw. gebrauchen 
können, das ist nicht falsch. Ich hatte das ohne weitere Erklärung so 
hingeworfen. Aber generell sollte der Code (wenn möglich) für sich 
selbst sprechen - durch seine Struktur und die Namen von Funktionen und 
Variablen etc. Für die Ausnahmen gibt es dann Kommentare. Außerdem kann 
man damit natürlich Funktionen bzw. Gruppen von Ausdrücken 
zusammenfassend beschreiben, auf Gefahren hinweisen u.a. Was sie nicht 
sollen: Verwirren (z.B. durch Mehrdeutigkeit) oder - im anderen Extrem - 
etwas Offensichtliches wiederholen.

> Zudem gibt es im Code meiner Meinung nach keine überflüssigen Kommentare.

Eher sogar recht viele - wobei ich das, wenn du wirklich für absolute 
Anfänger verständlich schreiben willst, evtl. etwas abschwächen muss.
Aber hier mal ein typisches Beispiel, das definitiv auch für Anfänger 
gilt:

// Hintergrund weiß färben
textBox1.Background = Brushes.White;

Der Kommentar ist gut gemeint, aber sinnlos, denn da steht bereits 
"Hintergrund = weiß" - also erhöht er nur das "Rauschen". Andererseits 
hast du die Textbox nicht umbenannt, so dass genau die einzige Frage, 
die man sich beim Betrachten des Codes irgendwann stellen könnte, 
nämlich welcher Hintergrund denn nun weiß wird, unbeantwortet bleibt 
(ohne nachzusehen).

Soll bloß eine kleine Anregung zum Nachdenken sein, weil deine Antwort 
darauf schließen lässt, dass du dir einen solchen Kommentarstil - in der 
festen Überzeugung, dass er gut wäre -, angewöhnen könntest.

von Rainer V. (rudi994)


Lesenswert?

Daniel M. schrieb:
> Im Programmcode werden Kommentare ja grün
> dargestellt und heben sich somit vom Funktionscode deutlich ab.

Das ändert sich, wenn man einen langen Quelltext mit vielen Kommentaren 
z.B. als Hilfe beim Programmieren im Windows Notepad öffnen möchte und 
dann nur noch schwarze Schrift auf weissem Hintergrund hat.

von Daniel M. (daniel_91)


Lesenswert?

AmanitaMuscaria schrieb:
> Gut, freut mich. Manchmal hängt man bei solchen Dingen ewig fest. Ich
> würde aber empfehlen, auch die anderen Sachen zu ändern, falls du es
> noch nicht gemacht hast:

[...]

> Wenn das Programm umfangreicher werden sollte, könnte man SerialPort und
> die ganze Kommunikation aus dem Fenster herausnehmen. Puristen würden
> vermutlich anmerken, dass so etwas "nie" direkt in den Code der
> Fensterklasse bzw. überhaupt die GUI gehört, aber bei einem kleinen
> Programm muss man meiner Meinung nach nicht päpstlicher als der Papst
> sein.

Der hier gepostete Code ist nur ein sehr kleiner Auszug aus einem doch 
sehr umfangreichen Programm, aber zur Demonstration des Problems, habe 
ich den Knackpunkt extrahiert.
Die geamte Kommunikation habe ich nun in eine eigene Klasse ausgelagert 
und komplett von der Fenster-Klasse/ Benutzeroberfläche getrennt. Ist 
auch meiner Meinung nach deutlich sauberer so.
Auch habe ich beide Möglichkeiten ein Fenster zu schließen behandelt: In 
allen Fällen wird das Event gekündigt.
Da ich erst seit wenigen Wochen mit C# programmiere habe ich natürlich 
auch ein ganz anderes Gefühl für Kommentare, als ein Programmierer mit 
mehreren Jahren Berufserfahrung. Von daher wird sich das wohl im Laufe 
der Zeit noch ändern.

Danke nochmals für die Antworten

von Eisbeineis (Gast)


Lesenswert?

Daniel M. schrieb:
> Auch habe ich beide Möglichkeiten ein Fenster zu schließen behandelt: In
> allen Fällen wird das Event gekündigt.

Es gibt mehr, z.B. Alt-F4. Besser das Schließen-Event nutzen ...

von Daniel M. (daniel_91)


Lesenswert?

Eisbeineis schrieb:
> Es gibt mehr, z.B. Alt-F4. Besser das Schließen-Event nutzen ...

Genau damit habe ich das auch gemacht, das Event wird ja immer 
aufgerufen wenn ein Fenster geschlossen wird.

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.