Entwickler-Ecke
Basistechnologien - Elegantes Callback aus einem Thread zur GUI
jfheins - So 06.01.13 14:24
Titel: Elegantes Callback aus einem Thread zur GUI
Hi,
ich bin immer noch bei meinem tollen Programm und hätte da mal eine Frage zu "Eleganz" :)
Folgende Lösung funktioniert zwar, sieht aber nicht besonders hübsch aus:
C#-Quelltext
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:
| public partial class MainForm : Form { private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { var port = (SerialPort)sender; while (port.BytesToRead > 0) { Transmitter.ByteReceived((byte)port.ReadByte(), DisplayPacket); } } private void DisplayPacket(COMM_Header header, byte[] payload) { if (this.InvokeRequired) this.BeginInvoke(new DisplayDelegate(DisplayPacket), header); else info_textBox.AppendText("Paket empfangen: " + header.Type.GetInfo().DisplayName + "\n"); } }
public class Comm_Transmitter { public void ByteReceived(byte value, DisplayDelegate callback) { callback(RecHeader, null); } } |
Was mir jetzt einfällt: Das InvokeRequired kann vielleicht 'raus weil ich weiß dass es nötig ist. Das Formular weitergeben nur um damit dann BeginInvoke aufzurufen klingt noch uneleganter...?
Jetzt hatte ich mir überlegt, sowas wie "this.BeginInvoke(new DisplayDelegate(DisplayPacket), ...)" als callback zu übergeben. Sieht aber wieder umständlich aus mit zwei verketteten delegaten...
Wie macht ihr sowas?
Christian S. - So 06.01.13 14:57
Hallo!
Ich schreibe mir immer ganz gerne generische Methoden, die mir den Aufruf im GUI-Thread vereinfachen. Zum Beispiel so:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| public void Invoke<T>(Action<T> action, T param) { if (this.InvokeRequired) Invoke(action, param); else action(param); }
private void DisplayPacket(COMM_Header header, byte[] payload) { Invoke((aHeader) => info_textBox.AppendText("Paket empfangen: " + header.Type.GetInfo().DisplayName + "\n"), header); } |
Generell finde ich, dass anonyme Methoden und Lambda-Ausdrücke bei Multithreading helfen, Code dort stehen zu haben, wo er von der Logik her stehen sollte :-)
Könntest Du nicht die gesamte ByteReceived-Methode bereits im GUI-Thread aufrufen oder dauert die zu lange und sollte parallel abgearbeitet werden?
Oder kann die ByteReceived-Methode nicht einfach den entsprechenden COMM_Header als Ergebnis zurück gegeben?
Viele Grüße,
Christian
jfheins - So 06.01.13 16:14
Hi,
Zitat: |
Könntest Du nicht die gesamte ByteReceived-Methode bereits im GUI-Thread aufrufen oder dauert die zu lange und sollte parallel abgearbeitet werden? |
So habe ich das jetzt gelöst :-)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { var port = (SerialPort)sender; while (port.BytesToRead > 0) { var data = (byte)port.ReadByte(); this.BeginInvoke((Action)(() => Transmitter.ByteReceived(data, DisplayPacket))); } } |
Dann wird zwar für jedes empfangene Byte der Hauptthread belästigt, aber das sollte bei unserer Datenrate noch machbar sein :P
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!