Autor Beitrag
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: So 06.01.13 14:24 
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:
ausblenden volle Höhe 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
{
  // Diese Methode wird duch den COM Port stats in einem seperaten Thread aufgerufen
  private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
  {
    var port = (SerialPort)sender;
    while (port.BytesToRead > 0)
    {
      Transmitter.ByteReceived((byte)port.ReadByte(), DisplayPacket);
    }
  }
  
  // Hier habe ich Zugriff auf this und kann daher BeginInvoke benutzen
  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
{
  // Demzufolge läuft auch diese Methode nicht im GUI Thread
  public void ByteReceived(byte value, DisplayDelegate callback)
  {
    // viel code
    // Hier habe ich keine referenz auf das Formular, daher kein BeginInvoke
    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.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: 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:

ausblenden 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

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".

Für diesen Beitrag haben gedankt: jfheins
jfheins Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: 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 :-)
ausblenden 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