Autor |
Beitrag |
oneitis
Hält's aus hier
Beiträge: 10
|
Verfasst: Di 16.03.10 15:11
Hallo liebe c-sharp community... das forum hier hat mir durchs lesen schon sehr viel geholfen  deswegen bin ich überhaupt so weit gekommen
Folgendes Programm A schickt über Com1 (der mit Com2 verbunden ist) den String "Testline" und Programm B soll diesen auf Com 2 empfangen.
Programm A funktioniert einwandfrei und sendet auf knopfdruck den String.
Programm B öffnet den Comport und wenn ich auf meinen readButton drücke schreibt mir das programm mit serialport1.readexisting() auch den String in meine Textbox. Jetzt wollt ich nur nicht jedes mal den Knopf drücken müssen um die Empfangenen Daten in die Textbox zu bringen.
Also habe ich (glaub ich eh von hier im forum abgeschaut) folgendes geschrieben:
C#-Quelltext 1: 2: 3: 4:
| void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { textBox1.AppendText(serialPort1.ReadExisting()); } |
Aber so bald er Datenempfängt, kommt die Fehlermeldung "Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement textBox1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."
Ich bin noch nicht wirklich lange bei csharp (oh wunder sonst würd ich ja nicht so ein topic eröffnen) und ja ich habe die suchfunktion und google verwendet.
Wenn ich mich nicht irre muss ich Delegate oder invoke dafür verwenden, doch damit hab ich onch nicht gearbeitet und ich habs versucht zu verstehen wie Delegate funktioniert aber so einfach war das nicht  da hat mir selbst mein schlaues buch nicht viel geholfen beim verstehen...
Hier der ganze code:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO.Ports;
namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void button3_Click(object sender, EventArgs e) { textBox1.Clear(); }
private void openb_Click(object sender, EventArgs e) {
serialPort1.PortName = "COM2"; serialPort1.BaudRate = 9600; serialPort1.DataBits = 8; serialPort1.Parity = Parity.None; serialPort1.StopBits = StopBits.One; serialPort1.ReadTimeout = 9000;
serialPort1.Open(); if (serialPort1.IsOpen) { textBox1.AppendText(serialPort1.PortName + " wurde geöffnet!\r\n"); } else { textBox1.AppendText(serialPort1.PortName + " konnte nicht geöffnet werden!\r\n"); }
serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialPort1_DataReceived); }
void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { textBox1.AppendText(serialPort1.ReadExisting()); }
private void closeb_Click(object sender, EventArgs e) { serialPort1.Close(); if (!serialPort1.IsOpen) { textBox1.AppendText(serialPort1.PortName + " wurde geschlossen!\r\n"); } } } } |
Normalerweise poste ich sowas nicht, weil ich theorethisch mit genug übung es selbst schaffen könnte, aber im moment hab ich keinen kopf dafür und ich wäre sehr erfreut wenn mir wer helfen könnte ^^
lg Kurt
|
|
danielf
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: Di 16.03.10 15:33
Hi,
da hast du vollkommen recht.
Um ein Delegate aufzurufen musst du es zuerst deklarieren. Das tust du so:
C#-Quelltext 1:
| private delegate void <name>Delegate(<params>) |
Im Code überprüfst du dann, ob ein Invoke für das Control benötigt wird.
C#-Quelltext 1:
| control.InvokeRequired |
Falls dies der Fall ist erstellst du ein Delegate von dem Typ wie du es oben angelegt hast:
C#-Quelltext 1:
| Delegate d = new <name>Delegate(<params>); |
und rufst es über die Invoke Methode des Controls auf (ansonsten normaler Zugriff)
C#-Quelltext 1:
| control.Invoke(d, <params>); |
Kann dann bei dir so aussehen:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { AppendText(textBox1, serialPort1.ReadExisting()); }
private delegate void AppendTextDelegate(TextBox textBox, string text);
private void AppendText(TextBox textBox, string text) { if (textBox.InvokeRequired) { textBox.Invoke(new AppendTextDelegate(AppendText), textBox, text); } else { textBox.AppendText(text); } } |
|
|
oneitis 
Hält's aus hier
Beiträge: 10
|
Verfasst: Di 16.03.10 17:47
Danke schön, jetzt funktionierts, ich habs zwar noch nicht ganz genau verstanden, aber ich hab gerade ein aha erlebnis gehabt
werd das ganze jetzt auseinander nehmen und so lang herum probieren bis ichs check
danke noch mal 
|
|
oneitis 
Hält's aus hier
Beiträge: 10
|
Verfasst: Mo 22.03.10 14:07
Ich habs echt versucht und auch teilweise verstanden, aber es klappt einfach nicht so wie ich will... hat jemand vielleicht einen link der delegate und die inwoke funktion genau erklärt?
mein problem is, dass ich ne eingabeaufforderung hab und auch result und eine variable brauche von der eingabe...
und diese dann in der hauptform in textfeld ausgegeben wird...
also hat wer nen link zum lernen?
ps: ja ich weiß man soll es nicht aber daweil hab ich das problem mit CheckForIllegalCrossThreadCalls = false; gelöst ^^
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mo 22.03.10 14:49
Zitat: | ps: ja ich weiß man soll es nicht aber daweil hab ich das problem mit CheckForIllegalCrossThreadCalls = false; gelöst ^^ |
Du hast das Problem nicht gelöst. Du hast dem Compiler der Laufzeitumgebung nur gesagt sie soll dir das Problem nicht mehr melden.
Weg gucken ohne sonstige Maßnahmen löst das Problem natürlich nicht wirklich.
Gewusst wie: Threadsicheres Aufrufen von Windows Forms-Steuerelementen
|
|
danielf
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: Mo 22.03.10 15:12
Das Gerüst habe ich dir ja schon aufgezeigt. Was hast du daraus gemacht? Wenn du uns deinen Code schickst, können wir dir bestimmt weiterhelfen.
|
|
oneitis 
Hält's aus hier
Beiträge: 10
|
Verfasst: Mo 22.03.10 16:01
Habs versucht aber klappt ned, morgen wird warscheinlich eh ein kollege vorbei kommen und es mir erklären
hier mal mein ganzer code vom versuch...(ab)zeile 132 und zeile 92 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO.Ports; using System.IO; using System.Data.SqlClient;
namespace WindowsFormsApplication1 { public partial class Form1 : Form { public string compuff; public string produktEingabe; public Form1() { InitializeComponent(); string[] ports = SerialPort.GetPortNames(); combox.DataSource = ports; }
private void button3_Click(object sender, EventArgs e) { textBox1.Clear(); }
private void openb_Click(object sender, EventArgs e) {
serialPort1.PortName = combox.SelectedValue.ToString() ; serialPort1.BaudRate = 9600; serialPort1.DataBits = 8; serialPort1.Parity = Parity.None; serialPort1.StopBits = StopBits.One; serialPort1.ReadTimeout = 9000;
try { serialPort1.Open(); } catch (IOException fehler) { MessageBox.Show(fehler.Message); } catch (UnauthorizedAccessException fehler2) { MessageBox.Show(fehler2.Message); } catch (Exception fehler3) { MessageBox.Show(fehler3.Message); }
if (serialPort1.IsOpen) { textBox1.AppendText(serialPort1.PortName + " wurde geöffnet!\r\n"); openb.Enabled = false; closeb.Enabled = true; combox.Enabled = false; } else { textBox1.AppendText(serialPort1.PortName + " konnte nicht geöffnet werden!\r\n"); }
serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialPort1_DataReceived); }
void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { compuff = serialPort1.ReadExisting(); AppendText(textBox1, compuff + "\r\n"); try { SqlConnectionStringBuilder sqlcon = new SqlConnectionStringBuilder(); sqlcon.DataSource = @"LAPTOP\SQLEXPRESS"; sqlcon.InitialCatalog = "readcom"; sqlcon.IntegratedSecurity = true; SqlConnection connect = new SqlConnection(sqlcon.ConnectionString); connect.Open(); if (connect.State == ConnectionState.Closed) { AppendText(textBox1, "Verbindung wurde nicht hergestellt!\r\n"); }
string check = "SELECT COUNT(*) " + "FROM readcomprodukte WHERE ID = '" + compuff + "'";
SqlCommand cmd = new SqlCommand(check, connect); int vorhanden = Convert.ToInt32(cmd.ExecuteScalar()); if (vorhanden == 0) { InputText(compuff); AppendText(textBox1, "Produkteingabe: " + produktEingabe); }
if (vorhanden == 1) { try { string read = "SELECT ID, Produkte " + "FROM readcomprodukte WHERE ID = '" + compuff + "'";
SqlCommand cmd4 = new SqlCommand(read, connect); SqlDataReader dr = cmd4.ExecuteReader(); while (dr.Read()) AppendText(textBox2,((string)dr["Produkte"])+"\r\n");
dr.Close(); connect.Close();
} catch (Exception sqlfehler) { MessageBox.Show(sqlfehler.Message); } }
if (vorhanden > 1) { AppendText(textBox1, "ID mehrfach vorhanden!"); } } catch (Exception sqlfehler) { MessageBox.Show(sqlfehler.Message); }
}
private delegate void AppendTextDelegate(TextBox textBox, string text); private delegate string InputTextDelegate(string compuff); private string InputText(string compuff) { inputdialog input = new inputdialog(compuff); input.Invoke(new InputTextDelegate(InputText), compuff);
if (input.InvokeRequired) { input.Invoke(new InputTextDelegate(InputText), compuff); }
return input.produktEingabe; }
private void AppendText(TextBox textBox, string text) { if (textBox.InvokeRequired) { textBox.Invoke(new AppendTextDelegate(AppendText), textBox, text); }
else { textBox.AppendText(text);
} }
private void closeb_Click(object sender, EventArgs e) { serialPort1.Close(); if (!serialPort1.IsOpen) { textBox1.AppendText(serialPort1.PortName + " wurde geschlossen!\r\n"); closeb.Enabled = false; openb.Enabled = true; combox.Enabled = true; } }
private void saveb_Click(object sender, EventArgs e) { saveFileDialog1.InitialDirectory = @"c:\"; saveFileDialog1.Filter = "Textdateien (*.txt)|*.txt|Alle Dateien (*.*)|*.*"; DialogResult erg = saveFileDialog1.ShowDialog();
if (erg == DialogResult.OK) { StreamWriter writer = new StreamWriter(saveFileDialog1.FileName, true); writer.WriteLine(textBox2.Text); writer.Close(); } }
private void sendB_Click(object sender, EventArgs e) { try { SqlConnectionStringBuilder sqlcon = new SqlConnectionStringBuilder(); sqlcon.DataSource = @"LAPTOP\SQLEXPRESS"; sqlcon.InitialCatalog = "readcom"; sqlcon.IntegratedSecurity = true; SqlConnection connect = new SqlConnection(sqlcon.ConnectionString); connect.Open(); if (connect.State == ConnectionState.Open) { textBox1.AppendText("Sql verbindung hergestellt!"); } else { textBox1.AppendText("Verbindung wurde nicht hergestellt!"); }
string read = "SELECT ID, Produkte " + "FROM readcomprodukte";
SqlCommand cmd = new SqlCommand(read, connect); SqlDataReader dr = cmd.ExecuteReader(); while (dr.Read()) AppendText(textBox2, ("\r\n" + (string)dr["ID"] + " " + (string)dr["Produkte"])); dr.Close(); connect.Close();
} catch (Exception sqlfehler) { MessageBox.Show(sqlfehler.Message); }
}
private void button1_Click(object sender, EventArgs e) { try { SqlConnectionStringBuilder sqlcon = new SqlConnectionStringBuilder(); sqlcon.DataSource = @"LAPTOP\SQLEXPRESS"; sqlcon.InitialCatalog = "readcom"; sqlcon.IntegratedSecurity = true; SqlConnection connect = new SqlConnection(sqlcon.ConnectionString); connect.Open(); if (connect.State == ConnectionState.Open) { textBox2.AppendText("Sql verbindung hergestellt!"); } else { textBox2.AppendText("Verbindung wurde nicht hergestellt!"); }
string read = "DELETE FROM readcomprodukte " + "WHERE ID='9001521000242'";
SqlCommand cmd = new SqlCommand(read, connect); cmd.ExecuteNonQuery(); connect.Close();
} catch (Exception sqlfehler) { MessageBox.Show(sqlfehler.Message); } } } } |
|
|
danielf
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: Mo 22.03.10 18:01
In zeile 117 überprüfst du, ob ein Invoke benötigt wird, aber in Zeile 116 führst du schon eins aus
Ausserdem rufst du ja in zeile 116 auch wieder die gleiche Methode auf.. und landest somit in einer Endlosschleife --> Stack overflow!
Bitte schau dir mein gerüst nochmal an, ich bin mir sicher wenn du dich ziemlich streng daran hälst bekommst du es hin.
Hier findest du auch noch ein buntes Beispiel.
Gruß
|
|
oneitis 
Hält's aus hier
Beiträge: 10
|
Verfasst: Do 01.04.10 10:01
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Do 01.04.10 21:33
Ich nehme mal an, dass die SQL-Abfrage nicht absichtlich im Nebenthread ausgeführt wird, warum also nicht in DataReceived sofort invoken und danach gemütlich im Hauptthread weiterprogrammieren 
_________________ >λ=
|
|
oneitis 
Hält's aus hier
Beiträge: 10
|
Verfasst: Fr 09.04.10 09:04
weil ich noch keine ahnung habe vom richtigen(effizienten) programmieren
Könnte ich es also so lösen: So bald die Daten vom Comport in die Variable geschrieben werden, wird ein Event ausgelöst. Mit diesen Event würde ich dann wiederum die Sql-Abfrage im Hauptthread starten. <-?
ps: vorteil? nachteil? keine ahnung wäre aber echt begeistert wenn mir wer den sinn dahinter erklärt... is sicher basic vom programmieren ^^
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Fr 09.04.10 13:50
|
|
oneitis 
Hält's aus hier
Beiträge: 10
|
Verfasst: Fr 09.04.10 14:50
Verdammt... also wenn das jetzt so funktioniert wie ich mir das vorstelle, dann hätte ich mir einiges ersparen können... (wobei ich sagen muss, sonst hätte ich nie so "viel" dazu gelernt)
Muss ich ausprobieren so bald ich wieder dazu komme, schaut sehr gut aus...
ps: danke für die erklärung, war echt noch nie in einem forum, wo einem wirklich so gut geholfen wurde... bzw. so konstruktive beiträge gepostet wurden 
|
|
|