Delegate Funktion an Konstruktor übergeben



  • Hallo,

    Ich habe folgendes Problem

    public partial class Form1 : Form
        {
            private ThreadHandling Rs232ThreadHandling;
    
            public Form1()
            {
    
                 Rs232ThreadHandling = new ThreadHandling(this,ReceiveRs232);   // wie muss ich ReceiveRs232 übergeben                        
    
            }
            public void ReceiveRs232(int RxData, int Lenght, int Cnt)
            {
                ........
            }
        }
    //---------------------------------------------------------------------------
        public class ThreadHandling
        {
            private DelegateReceiveRs232 Rs232ReceiveDelegate;
            public ThreadHandling(Form1 CtrForm, ???Target????)
            {
                Rs232ReceiveDelegate = new DelegateReceiveRs232(???Target????);
            }
    

    Wie übergebe ich ReceiveRs232 an den Konstruktor von ThreadHandling?



  • ublic class ThreadHandling
        {
            private DelegateReceiveRs232 Rs232ReceiveDelegate;
            public ThreadHandling(Form1 CtrForm, DelegateReceiveRs232 Rs232ReceiveDelegate)
            {
                this.Rs232ReceiveDelegate= Rs232ReceiveDelegate;
            }
    


  • 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


Anmelden zum Antworten