Event / Ereignis erstellen und abonnieren



  • Hallo Leute,

    ich versuche nun schon seit geraumer Zeit ein Ereignis in Projektdatei A zu erstellen und auf dieses Ereignis in Projektdatei B zu reagieren, doch es gelingt mir einfach nicht.

    Hintergrund ist folgender: Das Programm empfängt per USB-Schnittstelle Daten und je nachdem welche Daten ankommen, soll meine Form1, also mein grafisches Menü etwas spezielles anzeigen. Im einfachsten Fall ist dies: Wenn Datenpaket == X1, dann label1->Text="Paket X1 empfangen".

    Nun zum bisherigen Code:

    File: Programm.cpp, Hier ist die Ereignis erzeugende Klasse

    ref class EreignisProduzent
    {
    	//Delegatentyp für Ereignis
    	delegate void CanEmpfangEventHandler(System::Object ^source, System::EventArgs ^e);
    	//Ereignis
    	event CanEmpfangEventHandler ^OnCanEmpfang;
    
    public:
    
    	void Ereignis(void)
    	{
    		//Ereignis ist eingetreten, Abonnenten informieren
    		OnCanEmpfang(this, gcnew EventArgs());
    	}
    
    };
    

    In einem extra Thread frage ich ständig den Empfangspuffer der USB-Schnittstelle ab und erzeuge das Ereignis, sobald etwas empfangen wird:

    File: Programm.cpp

    void th_ThreadReceive()
    {
    	long lLen = 1;
    	CMSG t_CANMsg;  //Empfangs Datenpuffer
    	ULONG erg = 0;
    	EreignisProduzent ^Er = gcnew EreignisProduzent();  
    
    	while(1)
    	{			
                    //Auslesen des Puffers
    		erg = lpfncanRead(g_hHandle, &t_CANMsg, &lLen);
    		if(!erg)
    		{
    			if(t_CANMsg.l_id == 0x64)
    			{
    				if((t_CANMsg.aby_data[0] & 0x80)==0x80)
    				{
    					Er->Ereignis();
    				}
    			}
    		}
    		else
    		{
    			// falls Auslesen fails, beende thread
    			break;
    		}
    	}
    //	return 0;
    }
    

    Schließlich noch das Abonnieren des Ereignisses, also das darauf-reagieren:

    Form1.h:

    ref class EreignisProduzent;
    using namespace Projekt;
    public ref class Form1 : public System::Windows::Forms::Form
    	{
    		EreignisProduzent ^EreignisProduzentInstanz;
    
    	public:
    		//Konstruktor
    		Form1(EreignisProduzent ^EreignisProduzentInstanz);
    
    	protected:
    		//Destruktor
    		~Form1();
    
    	private: System::Windows::Forms::Button^  button1;
    	private: System::Windows::Forms::Label^  label1;
    	private: System::Windows::Forms::Button^  button2;
    
    	protected: 
    
    	private:
    
    		System::ComponentModel::Container ^components;
    
    #pragma region Windows Form Designer generated code
    
    		void InitializeComponent(void);
    
    #pragma endregion
    
    	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e);
    
    	public: System::Void UpdateLabels(String ^text) ;
    
    	private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e);
    
    	private: System::Void CanEmpfangsMethode(System::Object ^source, System::EventArgs ^e);
    
    };
    

    Form1.cpp: Konstruktor- und EreignisabhandlungsMethoden

    Form1::Form1(EreignisProduzent ^EreignisProduzentInstanz)
    		{
    			InitializeComponent();
    			this->EreignisProduzentInstanz = EreignisProduzentInstanz;
    			EreignisProduzentInstanz->Ereignis += gcnew EreignisProduzent::CanEmpfangEventHandler(this, &Form1::CanEmpfangsMethode);
    //error C2027, C2227
    
    		}
    
    	System::Void Form1::CanEmpfangsMethode(System::Object ^source, System::EventArgs ^e)
    	{
    			label1->Text = "Paket empfangen";
    	}
    

    Im bisherigen Code, erzeugt der Compiler in der Form1.cpp ein paar errors (C2027,C2227), welche besagen: Verwendung des undefinierten Typs "EreignisProduzent".
    Somit kennt er anscheinend beim konstruieren der Form1 noch nicht die Methoden der Klasse EreignisProduzent... leider weiß ich nicht wie ich diesen Fehler wegbekomme, hab schon bisschen was mit Vorwärtsdeklaration probiert, aber erfolglos.
    Kann mir hier jemand weiterhelfen? Wär ein Traum 🙂 weiß bald nimmer was ich noch probieren soll.



  • Ist EreignisProduzent ev in einem anderen Namespace?



  • Nein, sie befinden sich beide im selben namespace.
    Scheint halt wirklich das Prob zu sein, dass beim Aufruf des Konstruktors von Form1, die Definitionen von EreignisProduzent noch nicht bekannt sind.



  • Das gesamte Projekt steht als *.zip unter folgenden Link zum download bereit:

    http://codeschnipsel.co.de/Canfox_test_import2.zip



  • Sind denn die beiden Instanzen von EreignisProduzent identisch (im Thread und in Form1)? Du erzeugst ja im Thread eine neue Instanz davon.

    Du könntest alternativ das Event statisch (static) machen, jedoch trotzdem daran denken, daß das Event immer im Thread des Aufrufs ausgeführt wird (evtl. also Control.Invoke nötig!).



  • Die Instanzen von EreignisProduzent sind zwei verschiedene. In Thread ist es "^Er" und in Form1 "^EreignisProduzentInstanz", allerdings ist das in meinem schlauen Buch und in den Inet-Codes die ich fand ganauso gemacht. Ähm... Ein Event ist doch kein Objekt einer Klasse...oder? Aber so richtig verstehe ich diese Event Erzeugung und Abonnierung nicht. Ich stell mir diese Events wie Interrupts vor, welche alle Klassen "hören" (ob sie wollen oder nicht, also nicht durch if-then Anweisungen abgefragt, sondern sie kriegen es mit... wie auch immer sie das tun?) und entscheiden können, ob sie beim Auftreten eines bestimmten Events etwas tun oder nicht... kann sein dass ich mich da aber auch irre!?!
    Um zurück zum Prob zu kommen: Ich habe mittlerweile herausgefunden, dass dieser extra gestartete Thread ein Problem für das GUI in Form1 darstellt. Der Zugriff über Threadgrenzen hinweg auf Windows Forms Objekte ist nicht erlaubt. Dazu folgende Links:

    http://asadsiddiqi.wordpress.com/2007/12/24/responsive-user-interfaces-with-ui-threads/

    Siehe auch:
    http://msdn.microsoft.com/en-us/library/a82t6122

    Deshalb habe ich diesen Thread jetzt erstmal beseitigt und es in ein Standard ein-Thread-Programm umgeschrieben. In diesem Zuge habe ich auch den Event erstmal weggelassen, um erstmal ein ganz einfaches Programm zu schreiben, mit dem ich die Schnittstellenkommunikation testen kann. Und siehe da: es funktioniert schonmal 🙂
    Nun würde mich wieder dieses Event interessieren. Wie erstelle ich ein Event in einer Datei A, nennen wir sie "Test.cpp" und reagiere darauf in Datei B "Form1.cpp"? Die im bisherigen Quellcode aufgeführte Eventerzeugung und -benutzung ist 1zu1 aus dem Lehrbuch übernommen... aber sie funtkioniert nicht. Habe irgendwo noch nen falschen Fehler, wer den findet bekommt ein Eis! 😃



  • Seppel der Programmierer schrieb:

    Ich stell mir diese Events wie Interrupts vor, ...

    nein - bei einem Interrupt bleibt die komplette Abarbeitung im Kern der CPU stehen und es wird die entsprechende Interuptroutine abgearbeitet

    ... welche alle Klassen "hören" (ob sie wollen oder nicht, also nicht durch if-then Anweisungen abgefragt, sondern sie kriegen es mit wie auch immer sie das tun?) und entscheiden können, ob sie beim Auftreten eines bestimmten Events etwas tun oder nicht

    nein - es hören wirklich nur diese Klasse die das Event hören wollen ... dieser ganze Kapselung mit Events & Delegaten vereinfacht Dir die Sache nur

    wenn Du mal mit dem Listener-Prinzip unter Java gearbeitet hast, dann hast Du ein ungefähre Ahnung wie das unter .NET funktioniert ... hier wird dann jede Klasse abgearbeitet die das Event abboniert hat - vor allem passiert das Sequentiell ... wenn Du also das Event feuerst, dann werden erst die Methode in den einzelnen Klassen abgearbeitet und dann wird der folgende Befehle nach dem Auslösen des Events bearbeitet



  • Ich hatte vor kurzem einen Link für die Verwendung von Events gepostet: http://www.c-plusplus.net/forum/viewtopic-var-p-is-1939893.html#1939893


Anmelden zum Antworten