Delegate Funktion an Konstruktor übergeben
-
Ich habe das nun so gemacht, ist noch nicht ganz fertig
public partial class Form1 : Form { private Rs232Thread Rs232; public Form1() { InitializeComponent(); Rs232= new Rs232Thread(this, ReceiveRs232); Rs232.InitRs232("COM3", 57600); TxByte = 0xf1; Rs232.Rs232WriteByte(TxByte); } /// <summary> /// Rs232 Receive Event /// </summary> /// <param name="RxData"></param> public void ReceiveRs232(int RxData, int Lenght) { // tue etwas } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { Rs232.StopThread(); } } public class Rs232Thread { private Exception myException; Thread Thread; public delegate void DelegateReceiveRs232(int RxData, int Lenght); private DelegateReceiveRs232 Rs232ReceiveDelegate; /// <summary> /// Konstruktor /// </summary> /// <param name="CtrForm"></param> public Rs232Thread(Form1 CtrForm, DelegateReceiveRs232 Rs232Receive) { ControllForm = CtrForm; Rs232ReceiveDelegate = new DelegateReceiveRs232(Rs232Receive); Rs232 = new SerialPort(); Rs232CheckPorts(); } /// <summary> /// Init SerialPort /// </summary> /// <param name="Port"></param> /// <param name="Baudrate"></param> /// <returns></returns> public bool InitRs232(String Port,int Baudrate) { bool RetValue = false; Rs232.BaudRate = Baudrate; Rs232.PortName = Port; Rs232.ReadBufferSize = 2; Rs232.ReadTimeout = 500; Rs232.WriteTimeout = 500; try { Rs232.Open(); } catch (Exception e) { myExeption = e; // ControllForm.Invoke(ControllForm.Rs232ErrorDelegate, new Object[] { myExeption}); } if (!Rs232.IsOpen) RetValue = false; else { Thread = new Thread(new ThreadStart(Rs233ThreadFunction)); Thread.Start(); } return RetValue; } /// <summary> /// Schreibt ein Byte auf die serielle Schnittstelle /// </summary> /// <param name="Data"></param> public void Rs232WriteByte(byte Data) { TxBuffer[0] = Data; if(Rs232.IsOpen) Rs232.Write(TxBuffer, 0, 1); } /// <summary> /// Schließt den Port /// </summary> public void Rs232Close() { if (Rs232.IsOpen) Rs232.Close(); } /// <summary> /// Ermittelt alle vorhandenen Ports /// </summary> public void Rs232CheckPorts() { for (int Index = 0; Index < 10; Index++) { Rs232.PortName = stPorts[Index]; try { Rs232.Open(); ExistingPorts[Index] = true; Rs232.Close(); } catch (Exception e) { ExistingPorts[Index] = false; } } } /// <summary> /// Thread Stop /// </summary> public void StopThread() { Thread.Abort(); } /// <summary> /// ThreadFuntion /// </summary> public void Rs233ThreadFunction() { while(true) { try { if (true) { RxLenght = Rs232.BytesToRead; if (RxLenght != 0) { RxCnt++; Rs232Data = Rs232.ReadByte(); ControllForm.Invoke(Rs232ReceiveDelegate, new Object[] { Rs232Data, RxLenght}); } } } catch (ThreadAbortException) { // } catch (Exception e) { // } } } private int RxLenght; private int RxCnt; private Form1 ControllForm; private int Rs232Data; private SerialPort Rs232 = null; private byte[] TxBuffer = new byte[100]; public bool[] ExistingPorts = new bool[10]; private String[] stPorts = new String[] { "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "COM10", "COM11" }; private Exception myExeption; }
-
Joa das ist toll das du das so gemacht hast, aber du brauchst bei sowas nicht den ganzen Code zu posten, hier reicht uns deine überarbeitete Stelle
-
sorry
-
Nur zwei kleine Anmerkungen:
Es ist nicht gut der Hilfsklasse eine Referenz auf die Form zu übergeben. Erstelle lieber innerhalb von Rs232Thread ein event das die Form abonniert.
Man sollte Threads nicht mit Thread.Abort(); beenden. Das geht sehr viel sauberer und kontrollierter:
http://www.albahari.com/threading/part3.aspx#_Safe_Cancellation
-
... Erstelle lieber innerhalb von Rs232Thread ein event das die Form abonniert.
Zeig mal wie das geht, danke!
-
Nein machen wir nicht, bitte! Also sachmal ehrlich, bist du zu Faul um selber zu lernen?!
-
Ein Versuch war es ja Wert
Werde dann mal selber suchen.
-
hermes schrieb:
Zeig mal wie das geht, danke!
Hi hermes, ich kann dir folgende Seite empfehlen wenn du zum Thema Events mehr erfahren möchtest: http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx
Gruß!
-
Vielen Dank
-
Habe das ganze nun mal ausprobiert
public class Rs232Thread { .......... // Thread public void Rs233ThreadFunction() { while (true) { try { RxLenght = Rs232.BytesToRead; if (RxLenght != 0) { RxCnt++; _Rs232EventArgs.Rs232Data = Rs232.ReadByte(); if (Rs232Receive != null) Rs232Receive(this, _Rs232EventArgs); } } catch (Exception e) { // Hir kommt die Exeption } } } .......... } public partial class Form1 : Form { ....................... // Hier die Event Funktion public void ReceiveRs232(object sender, R232EventArgs e) { RxBuffer[BufferIndex] = Convert.ToByte(e.Rs232Data); setToolStripMenuItem.Enabled = true; Rs232.Rs232WriteByte(TxBuffer[BufferIndex]); return; } ............ }
Die Event Fuktion public void ReceiveRs232(object sender, R232EventArgs e) wird ausgeführt es kommt dann aber folgende Exeption im Thread
"Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement menuStrip1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."
Was muss ich da noch beachten?
-
Was muss ich da noch beachten?
Threading. Es gibt ein GUI Thread (mit deinem sichtbaren Fenster) und einen anderen Thread, der versucht etwas in Fenster ändern).Siehe http://msdn.microsoft.com/de-de/library/system.windows.forms.control.invoke.aspx
-
public partial class Form1 : Form { private void Form1_Load(object sender, EventArgs e) { ....... Rs232 = new Rs232Thread(this); Rs232.Rs232Receive += ReceiveRs232; ........ } public void ReceiveRs232(object sender, R232EventArgs e) { ..... setToolStripMenuItem.Enabled = true; infoToolStripMenuItem.Enabled = true; Offline = false; RxBuffer[BufferIndex] = Convert.ToByte(e.Rs232Data); Rs232.Rs232WriteByte(TxBuffer[BufferIndex]); } } public class R232EventArgs : EventArgs { public int RxLenght; public int Rs232Data; } public class Rs232Thread { public delegate void ReceivedEventHandler(object sender, R232EventArgs e); public event ReceivedEventHandler Rs232Receive; private R232EventArgs _Rs232EventArgs; private Form CtrForm; private Thread Thread; private delegate void DelegateReceiveRs232(R232EventArgs e); private DelegateReceiveRs232 Rs232ReceiveDelegate; public Rs232Thread(Form _CtrForm) { CtrForm = _CtrForm; Rs232ReceiveDelegate = new DelegateReceiveRs232(Rs232Rx); Rs232Receive = null; _Rs232EventArgs = new R232EventArgs(); Rs232 = new SerialPort(); Rs232CheckPorts(); } public bool InitRs232(String Port, int Baudrate) { ..... Thread = new Thread(new ThreadStart(Rs233ThreadFunction)); Thread.Start(); ....... } public void Rs233ThreadFunction() { while (true) { try { RxLenght = Rs232.BytesToRead; if (RxLenght != 0) { RxCnt++; _Rs232EventArgs.Rs232Data = Rs232.ReadByte(); CtrForm.Invoke(Rs232ReceiveDelegate, new Object[] { _Rs232EventArgs }); } } catch (Exception e) { RxCnt = 0; } } } protected void Rs232Rx(R232EventArgs e) { if (Rs232Receive != null) Rs232Receive(this, e); } }
So funktionierts, oder könnte es da irgend welche Probleme geben?
-
Das ist nicht gut.
Du musst dich entscheiden, entweder Control.Invoke oder Events (besser hier Events).z.B.: (ungetestet)
// Zeile 10: Rs232 = new Rs232Thread(); Rs232.Rs232Receive += ReceiveRs232; /*...*/ // BESSER: nicht public private void ReceiveRs232(object sender, R232EventArgs e) { // Ruft deinen Code im GUI-Context auf (geht besser über extrafunktion aber egal. if(InvokeRequired) { Invoke(ReceiveRs232, new Object[] {e}); return; } // dein code }
Ein paar Anmerkungen:
- schau dir mal den System.Windows.Forms.Backgroundworker an.
while (true)
catch (Exception e)
ist schlechter Stiel, genaue Fehlerklassen angeben. (Es gibt vielliecht Fehler, die du da nicht abfangen willst: z.B.:
Wenn - warum auch immer - der Stack voll ist und zwischen 73 - 80 eine Stackoverflow-Exception auslöst wird, kann dein Programm in einer Endlosschleife geraten)- Membervariablen kleinschreiben (Rs232Thread.Thread, Form1.Rs232 )
- eine Variable genau so wie ihren Typ zu benennen, zeugt nicht von wenig Fantasie. (macht auch ggf. Schwierigkeiten
(Gruß C++CLI)) public int RxLenght;
kapseln (public int Length { get; private set; } und im Konstruktor zuweisen)- Delegates außerhalb der Klasse
- Das Delegate im Thread bruchst du nicht, nimm
EventHandler<R232EventArgs>
- EventArgs jedesmal neu generieren (Vielleicht will der Empfänger die ja speichern - warum auch immer) und nicht als Instanzvariable
- Auf
Nullpointer
prüfen
Edit: Schlechtschreibkorretur