Windows Form stürzt ab beim lesen Serieller Daten

OP #4341394
Lesenswert?

Hallo,


wenn ich versuche die Daten von einer Seriellen Schnittstelle auf zu 
saugen und in eine ListBox zu schreiben, hängt sich meine Form ständig 
auf.
1
public void DataReceivedHandler(
2
object sender, SerialDataReceivedEventArgs e)
3
   {
4
       if (serialPort1.IsOpen)
5
       {
6
           Expander_1.Items.Add(serialPort1.ReadExisting());
7
        }
8
    }

Was mache ich falsch?
OP #4341540
Lesenswert?

Ich glaube das ist ein gutes Stichwort.
Könnte das was damit zu tun haben?
Hier ist übrigens die Fehlermeldung.
1
{"Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement Expander_1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."}


Wie kann ich das umgehen?
OP #4341678
Lesenswert?

Jens P. schrieb:
> Peter II schrieb:
>> Invoke/Delegate ist das Stichwort dafür,
>
> Alternativ geht auch diese Lösung. Ist allerdings ein bissel Pfusch...
>
> Control.CheckForIllegalCrossThreadCalls = False

Könntet ihr mal ein Beispiel anhand meines Problems geben?
Ich steige durch die ganzen Foren im Internet schon nicht mehr durch. 
Sitze schon > 9 Std. dran.

Kann doch wohl auch nicht so schwer sein.
OP #4341692
Lesenswert?

Sehe ich das richtig, dass es dieses Beispiel ist?
1
  // This event handler creates a thread that calls a 
2
// Windows Forms control in a thread-safe way.
3
private void setTextSafeBtn_Click(
4
  object sender, 
5
  EventArgs e)
6
{
7
  this.demoThread = 
8
    new Thread(new ThreadStart(this.ThreadProcSafe));
9

10
  this.demoThread.Start();
11
}
12

13
// This method is executed on the worker thread and makes
14
// a thread-safe call on the TextBox control.
15
private void ThreadProcSafe()
16
{
17
  this.SetText("This text was set safely.");
18
}
#4341693
Lesenswert?

So schwer ist das aber nicht, es gibt im Netz recht viele Anleitungen 
dazu.

Control.CheckForIllegalCrossThreadCalls = False an erster Stelle im 
Form_Load-Sub und du kannst normal programmieren und brauchst dir keine 
Gedanken über die illegalen Thread-Calls machen. Allerdings kann man 
sich damit andere Probleme einhandeln, deshalb ist diese Lösung mit 
Vorsicht zu verwenden.
Gast #4341696
Lesenswert?

Jan H. schrieb:
> Könntet ihr mal ein Beispiel anhand meines Problems geben?
> Ich steige durch die ganzen Foren im Internet schon nicht mehr durch.
> Sitze schon > 9 Std. dran.
>
> Kann doch wohl auch nicht so schwer sein.

Nein, ist auch wirklich ganz simpel. Zwei Tipps: Wenn du für son Kram 
über 9 Stunden brauchst, fehlen dir ganz offensichtlich wesentliche 
Grundlagen, vor allem zur Funktion des .NET Frameworks, aber auch zur 
Bedienung von Suchmaschinen wie z.B. Google.

Google "serialport datareceived c#" liefert an die 50 000 Treffer, unter 
den ersten 5 wird dein Prblem 3 mal gelöst.

z.B. 
http://stackoverflow.com/questions/26919090/serial-port-data-received-event-handler

http://stackoverflow.com/questions/11590945/how-to-display-the-data-read-in-datareceived-event-handler-of-serialport

Beitrag "C# SerialPort aus lesen"

Weil heut Sonntag ist, zitiere ich mal aus dem genannten µc.net Thread:
1
using System;
2
using System.Windows.Forms;
3
using System.IO.Ports;
4

5
namespace SerialPortWinForms
6
{
7
  public partial class Form1 : Form
8
  {
9
    SerialPort myport;
10
    delegate void UpdateCallback(string s);
11
    
12
    public Form1()
13
    {
14
      InitializeComponent();
15
      myport = new SerialPort("com1", 9600);
16
      myport.DataReceived += OnDataReceived;
17
      myport.Open();
18
    }
19

20
    void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
21
    {
22
      SerialPort sp = (SerialPort) sender;
23
      textBox1.Invoke(new UpdateCallback(this.UpdateTheTextbox), sp.ReadExisting());
24
    }
25

26
    void UpdateTheTextbox(string s)
27
    {
28
      textBox1.Text += s;
29
    } 
30
  }
31
}

Ansonsten hilft es auch oft, einfach mal 15 Minuten PAUSE zu machen.
OP #4341719
Lesenswert?

GeneigterLeser schrieb:
> void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
>     {
>       SerialPort sp = (SerialPort) sender;
>       textBox1.Invoke(new UpdateCallback(this.UpdateTheTextbox),
> sp.ReadExisting());
>     }
>
>     void UpdateTheTextbox(string s)
>     {
>       textBox1.Text += s;
>     }

Ich sollte wirklich mal eine Pause machen.

Den Port schließe ich dann einfach mit
1
myport.close();

oder muss ich hier auch noch was beachten?
Gast #4341764
Lesenswert?

Jan H. schrieb:
> Es stürzt nach mehrmaligen Testen auch wieder ab.
man könnte auch mal Fehlermeldungen abfangen (Try Catch)

Vermutlich kommt jetzt ein anderen Fehler. "Stützt ab" ist keine 
hilfreiche Aussage.

> Die Lösungen klappen auch nicht 100%ig.
doch machen sie, wenn man es richtig macht
Gast #4341993
Lesenswert?

So, und solltest du es bis morgen nicht am laufen haben, möchte ich dir 
den durchaus gut gemeinten rat geben, es erstmal in vb.net zu versuchen.

dafür gibt es nochmal mehr beispiele zu diesem thema, die SOFORT 
funktionieren.

ausserdem ist die sprache für absolute anfänger leichter zu verstehen.

wobei es hier ja nun ein grundlegendes problem gibt, das du erstmal 
analysieren und verstehen solltest.
Gast #4341998
Lesenswert?

GeneigterLeser schrieb:
> So, und solltest du es bis morgen nicht am laufen haben, möchte ich dir
> den durchaus gut gemeinten rat geben, es erstmal in vb.net zu versuchen.

nein.

Es ja nur der Syntax anders, das verhalten ist identisch zu C#. Es macht 
für diesen Problem überhaupt keine Sinn auf VB zu gehen. VB macht nur 
für Leute sinn die vorher auch VB gemacht haben.

Die Hauptsprache für .net ist C# dafür findet man auch die meisten 
Einträgen in Foren.

VB entspricht von Syntax keiner der große Programmiersprachen, da ist 
immer alles anders. Damit kann man das Wissen nirgends mehr verwenden.
Gast #4342008
Lesenswert?

> Es ja nur der Syntax anders, das verhalten ist identisch zu C#.

Korrekt.

> VB entspricht von Syntax keiner der große Programmiersprachen, da ist
> immer alles anders. Damit kann man das Wissen nirgends mehr verwenden.

Mir scheint hier nunmal ein leidlich begabter c&p "programmierer" am 
werk zu sein, da wird es kaum schaden, wenn er eine sprache benutzt, die 
für ihn leichter verständlich ist.

zum lernen der absoluten basics halte ich vb immernoch für tauglich. 
nebenbei lernt er die strukturen des .net kennen, was viel wichtiger 
ist.

wenn er dann erste erfolgserlebnisse hatte, kann er ja immernoch auf c# 
portieren und dabei weiter lernen.
OP #4342133
Lesenswert?

Habt ihr euch denn überhaupt mal mein Programm angeschaut und gestartet 
bevor ihr hier Urteilt?

Mich würde mal interessieren, warum das so nicht klappt. Habe mich wie 
oben beschrieben ( GeneigterLeser: zitierter Code ) eigentlich dran 
gehalten.

Klar muss ich noch viel lernen bevor ich C# einigermaßen kann.
Darum frage ich hier auch mal vorsichtig nach.

Würde mich echt freuen, wenn ihr euch das Programm mal anschaut und mir 
nen Tipp gibt, warum dies immer noch nach wie vor hängen bleibt.
Gast #4342165
Lesenswert?

Jan H. schrieb:
> Habt ihr euch denn überhaupt mal mein Programm angeschaut und gestartet
> bevor ihr hier Urteilt?
ja

> Mich würde mal interessieren, warum das so nicht klappt. Habe mich wie
> oben beschrieben ( GeneigterLeser: zitierter Code ) eigentlich dran
> gehalten.
der vorschlag war aber nicht gut. Es ist nicht ohne Grund abgeschaltet.

> Würde mich echt freuen, wenn ihr euch das Programm mal anschaut und mir
> nen Tipp gibt, warum dies immer noch nach wie vor hängen bleibt.
wie schon geschrieben, es Programm bleibt nicht ohne Grund hängen. Wenn 
ja dann muss du uns die Zeile nennen wo es hängt.

Und eine Fehlerbehandlung fehlt immer noch.
OP #4342166
Lesenswert?

Peter II schrieb:
>> Mich würde mal interessieren, warum das so nicht klappt. Habe mich wie
>> oben beschrieben ( GeneigterLeser: zitierter Code ) eigentlich dran
>> gehalten.
> der vorschlag war aber nicht gut. Es ist nicht ohne Grund abgeschaltet.

Dieser Vorschlag ist nicht gut? Glaube du meinst wohl das mit dem 
ausschalten der Prüfung?!
1
using System;
2
using System.Windows.Forms;
3
using System.IO.Ports;
4

5
namespace SerialPortWinForms
6
{
7
  public partial class Form1 : Form
8
  {
9
    SerialPort myport;
10
    delegate void UpdateCallback(string s);
11
    
12
    public Form1()
13
    {
14
      InitializeComponent();
15
      myport = new SerialPort("com1", 9600);
16
      myport.DataReceived += OnDataReceived;
17
      myport.Open();
18
    }
19

20
    void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
21
    {
22
      SerialPort sp = (SerialPort) sender;
23
      textBox1.Invoke(new UpdateCallback(this.UpdateTheTextbox), sp.ReadExisting());
24
    }
25

26
    void UpdateTheTextbox(string s)
27
    {
28
      textBox1.Text += s;
29
    } 
30
  }
31
}
Gast #4342171
Lesenswert?

Jan H. schrieb:
> Dieser Vorschlag ist nicht gut? Glaube du meinst wohl das mit dem
> ausschalten der Prüfung?!

der code sieht auf den ersten Blick gut aus.

Was passiert nun. Kommt eine Fehlermeldung und "hängt" das Programm?

Wenn eine Fehlermeldung kommt, bei welcher Zeile und wie heißt die 
Exception?

Wenn es hängt, bei welcher Zeile hängt es?
Gast #4342308
Lesenswert?

1
public delegate void AddDataDelegate(String myString);
2
public AddDataDelegate myDelegate;
3

4
private void Form1_Load(object sender, EventArgs e)
5
{
6
    //...
7
    this.myDelegate = new AddDataDelegate(AddDataMethod);
8
}
9

10
public void AddDataMethod(String myString)
11
{
12
    textbox1.AppendText(myString);
13
}
14

15
private void mySerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
16
{
17
   SerialPort sp = (SerialPort)sender;
18
   string s= sp.ReadExisting();
19

20
   textbox1.Invoke(this.myDelegate, new Object[] {s});       
21
}
OP #4342844
Lesenswert?

mal hängt er sich hier auf (laut Debugger),  wenn ich den Port schließen 
will aber nur!
1
        void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
2
        {
3
            try
4
            {
5
                SerialPort sp = (SerialPort)sender;
6
//HIER                                                                        Expander_1.Invoke(new                                                                       UpdateCallback(this.UpdateTheTextbox), sp.ReadExisting());
7
            }
8
            catch (Exception ex)
9
            {
10
                MessageBox.Show(ex.Message);
11
            }
12

13
        }

mal hier...

1
        private void button1_Click_1(object sender, EventArgs e)
2
        {
3
            try
4
            {
5
                myport.DataReceived -= OnDataReceived;
6
                // MAL HIER
7
                myport.Close();
8
                MessageBox.Show("Close");
9
            }
10
            catch (Exception ex)
11
            {
12
                MessageBox.Show(ex.Message);
13
            }
14

15
        }
Gast #4342861
Lesenswert?

das an und abmelden brauchst du nur einmal für das Serial-Objekt zu 
machen. Ich würde sogar sagen das abmelden braucht man überhaupt nicht.

Es könnte sein das du dir selber im Weg stehst.

Das Abmelden vom Event erzeugt eventuell noch ein letzen Event. Was dann 
wiederum die GUI ansprechen will. Das geht aber nicht weil du noch der 
Funktion button1_Click_1 drin bist.
OP #4342881
Lesenswert?

Peter II schrieb:
> das an und abmelden brauchst du nur einmal für das Serial-Objekt
> zu
> machen. Ich würde sogar sagen das abmelden braucht man überhaupt nicht.
>
> Es könnte sein das du dir selber im Weg stehst.
>
> Das Abmelden vom Event erzeugt eventuell noch ein letzen Event. Was dann
> wiederum die GUI ansprechen will. Das geht aber nicht weil du noch der
> Funktion button1_Click_1 drin bist.

Auch wenn ich es raus nehmen mal geht es 2 - 3 mal (öffnen/schließen) 
dann mal wieder nicht. Das mit dem ab Abonnieren, habe ich raus 
genommen.
OP #4342902
Lesenswert?

Peter II schrieb:
> wenn du die Zeile
>
>>  textbox1.Invoke(this.myDelegate, new Object[] {s});
>
> auskommentierst, hängt er dann immer noch?

Nein. Dann klappt das wunderbar. Ich sollte mal meinen Aktuellen Code 
posten.
1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Data;
5
using System.Drawing;
6
using System.Linq;
7
using System.Text;
8
using System.Threading.Tasks;
9
using System.Windows.Forms;
10
using System.IO.Ports;
11
using System.Threading;
12
using System.IO;
13

14
namespace LED_ScannerV1._0
15
{
16

17
    public partial class Form1 : Form
18
    {
19
        SerialPort myport;
20
        delegate void UpdateCallback(string s);
21

22
        public Form1()
23
        {
24
            InitializeComponent();
25
            myport = new SerialPort("com5", 9600);
26
            myport.DataReceived += OnDataReceived;
27
            myport.Open();
28
            foreach (string item in System.IO.Ports.SerialPort.GetPortNames())
29
            {
30
                all_comports.Items.Add(item);
31
            }
32
        }
33

34
        private void Form1_Load(object sender, EventArgs e)
35
        {
36
        }
37

38
        void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
39
        {
40
            try
41
            {
42
                SerialPort sp = (SerialPort)sender;
43
                //Expander_1.Invoke(new UpdateCallback(this.UpdateTheTextbox), sp.ReadExisting());
44
            }
45
            catch (Exception ex)
46
            {
47
                MessageBox.Show(ex.Message);
48
            }
49

50
        }
51

52
        void UpdateTheTextbox(string s)
53
        {
54
            try
55
            {
56
                 Expander_1.Items.Add(s);
57
            }
58
            catch (Exception ex)
59
            {
60
                MessageBox.Show(ex.Message);
61
            }
62

63
        }
64

65
        private void button1_Click(object sender, EventArgs e)
66
        {
67
            foreach (string item in System.IO.Ports.SerialPort.GetPortNames())
68
            {
69
                all_comports.Items.Add(item);
70
            }
71
        }
72

73
        private void com_port_open_button_Click(object sender, EventArgs e)
74
        {
75
            try
76
            {
77
                myport = new SerialPort("com5", 9600);
78
                myport.DataReceived += OnDataReceived;
79
                myport.Open();
80
            }
81
            catch(Exception ex)
82
            {
83
                MessageBox.Show(ex.Message);
84
            }
85

86
        }
87

88
        private void button1_Click_1(object sender, EventArgs e)
89
        {
90
            try
91
            {
92
                myport.Close();
93
                MessageBox.Show("Close");
94
            }
95
            catch (Exception ex)
96
            {
97
                MessageBox.Show(ex.Message);
98
            }
99

100
        }
101
    }
102
}
Gast #4342906
Lesenswert?

ändere es mal so ab, wie es von MS empfohlen ist.

https://msdn.microsoft.com/de-de/library/ms171728(v=vs.110).aspx

> SerialPort sp = (SerialPort)sender;
> Expander_1.Invoke(new UpdateCallback(this.UpdateTheTextbox), sp.ReadExisting());

SerialPort sp = (SerialPort)sender;
if (this.Expander_1.InvokeRequired)
  {
    Expander_1.Invoke(new UpdateCallback(this.UpdateTheTextbox), 
sp.ReadExisting());
} else{
    UpdateTheTextbox(sp.ReadExisting());
  }
}
OP #4342912
Lesenswert?

Peter II schrieb:
> ändere es mal so ab, wie es von MS empfohlen ist.
>
> https://msdn.microsoft.com/de-de/library/ms171728(...
>
>> SerialPort sp = (SerialPort)sender;
>> Expander_1.Invoke(new UpdateCallback(this.UpdateTheTextbox), 
sp.ReadExisting());
>
> SerialPort sp = (SerialPort)sender;
> if (this.Expander_1.InvokeRequired)
>   {
>     Expander_1.Invoke(new UpdateCallback(this.UpdateTheTextbox),
> sp.ReadExisting());
> } else{
>     UpdateTheTextbox(sp.ReadExisting());
>   }
> }

Leider ja.
Läuft auch nicht stabil :(
Gast #4342935
Lesenswert?

So, habe nochmal ein bischen in meiner Codekiste gewühlt. Das ist zwar 
VB.NET, funktioniert aber einwandfrei. Ist natürlich nur ein Ausschnitt.
Mach mal ein gaaanz einfaches Form mit nur dem allernötigsten. Also dem 
comport, einem connect button und ner textbox.
Comportname, etc. alles hardcoden.

Dann fügst du das hier mal ein und guckst was passiert. Evtl. musst du 
ein bischen was umbennen oder löschen.
1
    Dim indata As String
2
    Private Sub SerialPort_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
3
        indata = SerialPort1.ReadExisting()
4
        Me.Invoke(New EventHandler(AddressOf DoUpdate))
5
    End Sub
6

7
    Public Sub DoUpdate()
8
        If CheckBox1.Checked = True Then TextBox1.AppendText(TimeOfDay & vbCrLf)
9
        TextBox1.AppendText(indata)
10
        TextBox1.Select(TextBox1.TextLength, 0)
11
        TextBox1.ScrollToCaret()
12
    End Sub

Telerik macht dadraus:
1
string indata;
2
private void SerialPort_DataReceived(System.Object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
3
{
4
  indata = SerialPort1.ReadExisting();
5
  this.Invoke(new EventHandler(DoUpdate));
6
}
7

8
public void DoUpdate()
9
{
10
  if (CheckBox1.Checked == true)
11
    TextBox1.AppendText(TimeOfDay + Constants.vbCrLf);
12
  TextBox1.AppendText(indata);
13
  TextBox1.Select(TextBox1.TextLength, 0);
14
  TextBox1.ScrollToCaret();
15
}
#4343016
Lesenswert?

Nicht jedesmal ein neues Objekt erzeugen könnte helfen...
1
 
2
public Form1() {
3
    InitializeComponent();
4
    myport = new SerialPort("com5", 9600);
5
    myport.DataReceived += OnDataReceived;
6
    myport.Open();
7
}
8

9
private void com_port_open_button_Click(...) {
10
    if (myport.IsOpen) return;
11
    myport.Open();
12
}
13

14
private void button1_Click_1(...) {
15
    myport.Close();
16
}
17

18
// oder so etwas
19

20
private void PortSettingsChanged(string newPortName) {
21
    if (newPortName == null) throw/return/MessageBox ...
22
   
23
    myport.Close();
24
    myport.PortName = newPortName;
25
    // change other settings
26
    myport.Open();
27
}
Gast #4343017
Lesenswert?

Moin,

Ich bin mir nicht ganz sicher. Du verwirfst ja den alten Port nicht 
richtig. Es kann durchaus sein, dass du da zwei Objekte hast, die sich 
stören, weil der Garbage Collector noch nicht so schnell war.
1
private void com_port_open_button_Click(object sender, EventArgs e)
2
{
3
  try
4
  {
5
    myport = new SerialPort("com5", 9600);
6
    myport.DataReceived += OnDataReceived;
7
    myport.Open();
8
  }
9
  catch(Exception ex)
10
  {
11
    MessageBox.Show(ex.Message);
12
  }
13
}

änder das mal in
1
private void foo(object sender, EventArgs e){
2
     if (myPort != null && !myPort.isOpen){
3
            myPort.Open();
4
     } 
5
}

das new kannst du dir an der Stelle sparen.

Wichtig. Du must bei dem SerialPort immer schauen, ob deine Variable 
nicht grad null ist oder der Port schon belegt.

Bei .Close musst du auch noch einen Check einführen.

PS: Kleiner Hinweis am Rande:
1
              all_comports.Items.AddRange(SerialPort.GetPortNames());

ist einfacher. Und GetPortNames liefert nicht immer gültige Namen 
zurück.

https://www.google.de/?gws_rd=ssl#q=c%23+trouble+getportnames
OP #4343022
Lesenswert?

> änder das mal inprivate void foo(object sender, EventArgs e){
>      if (myPort != null && !myPort.isOpen){
>             myPort.Open();
>      }
> }
>
> das new kannst du dir an der Stelle sparen.
>
> Wichtig. Du must bei dem SerialPort immer schauen, ob deine Variable
> nicht grad null ist oder der Port schon belegt.
>
> Bei .Close musst du auch noch einen Check einführen.
>


nach wie vor...
#4346759
Lesenswert?

Falls die Frage noch aktuell ist, zuerst würde ich eine Stringvariable 
als Puffer verwenden, wenn Daten kommen, und nicht den Port an die 
Textbox schicken.
1
 SerialPort sp = (SerialPort)sender;
2
    Expander_1.Invoke(new UpdateCallback(this.UpdateTheTextbox), sp.ReadExisting());

zu
1
string bfr = ((SerialPort)sender).ReadExisting();
2
Expander_1.Invoke(new UpdateCallback(this.UpdateTheTextbox),bfr);

Dann würde ich hinter das close() ein myport.Dispose() setzen um sicher 
zu gehen dass der Port seine Ressourcen sofort frei gibt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren