Delegate Funktion an Konstruktor übergeben



  • 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


Anmelden zum Antworten