Forum: PC-Programmierung C#.Hilfe.Eventhandler dreht sich im Kreis


von Benjamin L. (benjamin_l956)


Lesenswert?

Hallo liebe Gemeinde, ich möchte mich erst einmal einmal vorstellen da 
dies mein erster Beitrag in diesem (in Foren allgemein) ist. Ich möchte 
mich noch als Programmieranfänger bezeichnen. Vor zwei Jahren habe ich 
durch den Wunsch nach einer eigener Heimautomatisierung und einer 
Berufsunfähigkeit (also genug zeit für das neue Hobby), angefangen mir 
das Programmieren in C und C# beizubringen. Das Programm (man könnte es 
auch mein Übungsstück nennen) wuchs immer weiter, bis ich jetzt der 
Meinung war dass diese "Wurst" bevor sie noch größer wird einmal in 
Saubere geschrieben werden sollte.
Und wie es immer ist, das letzte Schlüsselelement zum Fertigstellen des 
Grundsteins, kriege ich einfach nicht hin. Der Eventhandler.

Was will ich mit dem Eventhandler eigtlich lösen:

Der Multithread TcpServer tut sein dienst wunderbar und gibt auch schön 
alles was ich von den angebunden Geräten empfange brav an die klasse 
devider weiter. Diese soll nun die InStrings an die entsprechenden 
Klassen (für jedes angebundene Gerät eine Klasse) mit jeh einem Event 
weiterleiten.


Der Versuch, angelehnt an dieses Beispiel

https://msdn.microsoft.com/de-de/library/system.eventhandler%28v=vs.110%29.aspx

sollte erstmal von der klasse "devider" (provider) ein event in der 
Klasse "solar" (suscriber) auslösen und mit den dazugehörigen Args den 
instring der in der Klasse "solar" landen soll, übergeben.
Gesagt getan und siehe da es läuft nicht, nur einmal beim aufrufen der 
Form "solar" und danach nie wieder.
Beim ganzen vor und zurückschrauben der Fehlersuche ist mir dann erstmal 
klar geworden was das Event eigentlich auslöst und warum es auch 
Callback genannt wird. Da beist sich die Katze in den Schwanz....
Daher zum Kern des Problems, so wie es jetzt ist (code hänge ich an) ist 
das ganze für mich unbrauchbar. Aber was ist die Lösung, ich hab grad 
null Ansätze. Sollte ich hier besser einfach Delegates verwenden oder 
habe ich das Thema Eventhandler falsch verstanden?
 Jedenfalls habe ich mir das gesamte Wochenende inklusive durch ehrgeiz 
provozierten schlafmangel um die Ohren gehauen und alles was der Freund 
Google so hergegeben hat gelesen und ausprobiert. Auch sämtliches hier 
aus dem Forum.
Soviel zur Problembeschreibung aber Code sagt ja mehr als tausend Worte.

vielen Dank schonmal im Vorraus und nun hier die Schnipsel



von hier kommt der string////////////////////////

public class bridge
    {
        public static string outstring;
        public static string instring;


        #region set tcpServer

        public static void set_outstring(string value)
        {
            outstring = value;
        }

        public static void set_instring(string value)
        {
            instring = value;
            InStringCaster();
        }

        #endregion
        #region set devider
        public static void InStringCaster()
        {


            if (instring != null)
            {
                string isc = instring;

                char splitter = '#';
                string[] splitstring = isc.Split(splitter);



                switch (splitstring[0])
                {
                    case "Arduino1":
                        devider dev1 = new devider();
                        dev1.dev1(instring);
                        break;

                    case "Arduino2":
                        devider dev2 = new devider();
                        dev2.dev2(instring);
                        // adminchar = splitstring[0];
                        break;

                    case "Arduino3":
                        devider dev3 = new devider();
                        dev3.dev3(instring);
                        break;
                }


                devider op = new devider();
                op.Admin();
            }
            #endregion
        }
    }




Diese Klasse soll das event in der Klasse "solar" auslösen sobald der 
instring für das gerät eintrifft und diesen übergeben

 class devider
    {


        #region Strom

        protected virtual void 
OnInString_powermeter_main_Reached(powermeter_mainArgs e)
        {
            EventHandler<powermeter_mainArgs> handler = 
InString_powermeter_main_Reached;
            if (handler != null)
            {
                handler(this, e);
            }
        }
        public event EventHandler<powermeter_mainArgs> 
InString_powermeter_main_Reached;

        public void dev1(string instring)
        {
            powermeter_mainArgs powermeter_mainargs = new 
powermeter_mainArgs();
            powermeter_mainargs.InString_powermeter_main = instring;

            OnInString_powermeter_main_Reached(powermeter_mainargs);


        }
        #endregion
        #region solar
        public void dev2(string instring)
        {

            SolarArgs solarargs = new SolarArgs();
            solarargs.InString_Solar = instring;

            OnInString_Solar_Reached(solarargs);
            //MessageBox.Show("void dev2");
        }



         void OnInString_Solar_Reached(SolarArgs e)
        {
            EventHandler<SolarArgs> handler = InString_Solar_Reached;

            try {
                handler(this, e);

                MessageBox.Show("handler is != null");
            }
            catch { MessageBox.Show("handler is null"); }
        }
        public event EventHandler<SolarArgs> InString_Solar_Reached;

        #endregion


        #region door

        public void dev3(string instring)
        {
            DoorArgs Doorargs = new DoorArgs();
            Doorargs.InString_Door = instring;

            OnInString_Door_Reached(Doorargs);


        }
        void OnInString_Door_Reached(DoorArgs e)
        {
            EventHandler<DoorArgs> handler = InString_Door_Reached;
            handler.Invoke(this, e);
        }
        public event EventHandler<DoorArgs> InString_Door_Reached;


        #endregion

        #region admin
        public void Admin()
        {
            /*
            AdminArgs adminargs = new AdminArgs();
            adminargs.InString_Admin = bridge.instring;
            adminargs.OutString_Admin = bridge.outstring;

            OnInString_Admin_Reached(adminargs);
*/
        }
        #endregion
    }




in dieser Form soll durch das event von der klasse "devider" der void 
InStringCaster aufgerufen werden um den instring zu verarbeiten

  public partial class solar : Form
    {

        #region deklaration


        public string isc2;
        public float grid_voltage;
        float grid_frequency;
        float AC_output_voltage;
        float AC_output_frequency;
        float Battery_voltage;
        float PV_input_voltage1;
        float Battery_input_voltage_SCC;

        int SBU_priority_version = 0;
        int config_Status = 0;
        int SCC_firmware_version = 0;
        int Load_status = 0;
        int battery_voltage_steady_charging = 0;
        string Charging_Status_Text = "";

        long AC_output_apparent_power;
        long AC_output_active_power;
        int Output_load_percent;
        float BUS_voltage;
        int Battery_charging_current;
        int Battery_capacity;
        float Inverter_heatsink_temperature;
        int PV_input_current_for_battery;
        int Battery_discarge_current;

        string PIP_Output_mode;

        string test = "0";
        string test1 = "0";
        string test2 = "0";
        string test3 = "0";
        string test4 = "0";




        public static string solarinstring;
        public static string InStringCasters;

        #endregion

        public solar()
        {
            InitializeComponent();


            devider dev = new devider();
            dev.InString_Solar_Reached += InString_Solar_Reached;


        }
        #region event



        static void InString_Solar_Reached(object sender, SolarArgs e)
        {


            // InStringCaster(e.InString_Solar);
            InStringCasters = e.InString_Solar.ToString();
            MessageBox.Show("Event Solar triggerd");
        }
        #endregion



        #region debug instring

        public void InStringCaster(string InString)
        {
            string[] isc;
            string OK = "(ACK9 ";
            char splitter = '#';
            isc = InString.Split(splitter);

try {
  if(isc[0]=="Arduino2")
 {
   switch (isc[1])
   {
        case "QPIGS":
            if (isc[2].Length > 0)
            {
                QPIG(isc[2]);
            }
            break;

            case "QMOD":
                QMOD(isc[2]);
             break;

            case "PCPuf":
                 if (isc[2] == OK) MessageBox.Show("change accepted");
            break;

            case "PCPsf":
                 if (isc[2] == OK) { }
                 MessageBox.Show("change accepted");
            break;

            case "PCPsu":
                 if (isc[2] == OK) MessageBox.Show("change accepted");
            break;

            case "PCPso":
                 if (isc[2] == OK) MessageBox.Show("change accepted");
            break;

            case "POPuf":
                 if (isc[2] == OK) MessageBox.Show("change accepted");
            break;

            case "POPsf":
                 if (isc[2] == OK) { }
                 MessageBox.Show("change accepted");
            break;

            case "POPsbu":
                 if (isc[2].Length > 0)
                 {
                 if (isc[2] == OK) MessageBox.Show("change accepted");
                 }
            break;

            case "Hello Server":
                 //MessageBox.Show("solar inverter connected");
            break;
            }
        }
    }
catch{ }
  }
}

von Oliver R. (superberti)


Lesenswert?

Hi,

ich glaube, Du hast eine komplett falsche Vorstellung davon, was ein 
Event ist und wann man diesen sinnvoll einsetzen kann.
Ein Event ist erst einmal nichts anderes als eine Liste von Delegaten, 
also Zeiger auf Funktionen von Klasseninstanzen.
Events (und Delegaten) sind immer dann sinnvoll, wenn die Klasse oder 
Komponente nicht weiss, wer sie mal später verwendet, man aber sicher 
ist, dem Benutzer der Komponente etwas mitteilen zu wollen.
Gerade Oberflächenkomponenten eignen sich dafür besonders gut, daher 
haben diese stets viele Events, an die man sich "dranhängen" kann. Das 
geht nicht nur mit einer Funktion, sondern mit (nahezu) beliebig vielen!
Events werden immer zur LAUFZEIT mit Delegaten bestückt, also z.B.

BlablaEvent += MeineFunktionInEinerKlasse;

Das kann ich in Deinen Quellen gar nicht finden, Deine Events sind 
schlicht leer!

Ich habe den zudem den Eindruck, dass Du das Ganze viel zu kompliziert 
angehst. Gib Deinen Objekten entsprechende Properties und setze die, 
wenn Daten empfangen werden. Du schreibst ja keine Komponenten, oder?

Gruß,
Oliver

von Benjamin L. (benjamin_l956)


Lesenswert?

hi, erstmal danke für die schnelle Antwort.

Klar da hast du natürlich recht, wie gesagt das ist der erste Versuch 
einen Eventhandler zu nutzen und zugegeben der code sieht natürlich 
verkompliziert aus, das sind alles gesäuberte Fragmente vom alten 
Programm. Die sollen nur dazu dienen das alles neu zu schreiben. Dazu 
kommt noch, dass ich vergessen hab die
 "public class SolarArgs : EventArgs
    {
        public string InString_Solar { get ;  set ;  }
    }"
 in den Post einzufügen. Es geht sich grade nur um den "Grundstein" in 
class solar : Form den void instringcaster aufzurufen und den instring 
zu verarbeiten.

"Events (und Delegaten) sind immer dann sinnvoll, wenn die Klasse oder
Komponente nicht weiss, wer sie mal später verwendet, man aber sicher
ist, dem Benutzer der Komponente etwas mitteilen zu wollen."

Trifft hier ja auch zu.
Den devider soll es nur einmal geben, für alle Forms. Man könnte das 
sicher umgehen in dem man einfach ALLES neuschreibt und ganz anders 
aufbaut aber der TCPServer und die Forms stehen(waren im code jetzt 
nicht sichtbar) und will zumindest an dem TCPServer nichts mehr ändern.

Richtig ist auch das Event übertrieben sind aber es kann ja nicht 
verkehrt sein events nutzen zu können da das Programm ja noch wesentlich 
mehr Teile hat und in Zukunft noch mehr dazu kommen sollen.
Im alten Programm lief das beim ersten Versuch, habe mich daher auch 
nicht näher damit beschäftigt und wollte das jetzt wieder so übernehmen, 
jedoch war es nicht reproduzierbar.


Verstehe nur deine Aussage nicht dass der Event leer ist.
Dein Beispiel "BlablaEvent += MeineFunktionInEinerKlasse;" findet man ja 
in class solar
 public solar()
        {
            InitializeComponent();


            devider dev = new devider();
            dev.InString_Solar_Reached += InString_Solar_Reached;


        }

Das Beispiel von MSDN funktioniert , es ist also alles da was man 
braucht. Ob es für meine Zwecke brauchbar ist, ist dann wieder ne andere 
Frage und kann ich auch noch nicht wirkich beurteilen.

Was für eine Lösung würde denn ein erfahrener Programmierer andenken  ?

edit: Es funktioniert jetzt.
Ich habe in class devider
public static event EventHandler<SolarArgs> InString_Solar_Reached;

als static geändert und in class solar

public solar()
        {
            InitializeComponent();
            devider.InString_Solar_Reached += InString_Solar_Reached;
        }
wird kein neues objekt mehr erstellt. Meintest du das mit "leeres Event" 
?

Was hälst du davon ?
egal wie ....Danke auf jeden Fall für die Hilfe

: Bearbeitet durch User
von Flox (Gast)


Lesenswert?

1
public solar()
2
{
3
  InitializeComponent();
4
5
  devider dev = new devider();
6
  dev.InString_Solar_Reached += InString_Solar_Reached;
7
}

Hmmm ... du erzeugst hier eine neue Instanz von devider, hängst dich in 
InString_Solar_Reached ein und wirfst die Instanz gleich wieder weg. dev 
sollte eigentlich Klassenmember sein, keine lokale Variable.

"Ob es für meine Zwecke brauchbar ist, ist dann wieder ne andere
Frage und kann ich auch noch nicht wirkich beurteilen."

Events sind schon ok.

"Ich habe in class devider public static event EventHandler<SolarArgs> 
InString_Solar_Reached; als static geändert"

Man muss nicht alles static machen, was bei drei nicht auf dem nächsten 
Baum ist ... ;). Wie gesagt, verwende ganz normale Klassenmember.
Ich verstehe u.a. auch noch nicht ganz, warum du immer wieder neue 
Instanzen von devider ("divider", ich würde es aber evtl. eher 
"Distributor", "Broker" o.ä. nennen) erzeugst und wieder wegschmeißt:

devider dev1 = new devider();
dev1.dev1(instring);

devider dev2 = new devider();
dev2.dev2(instring);

devider dev3 = new devider();
dev3.dev3(instring);

devider op = new devider();
op.Admin();

Es sollte doch eigentlich nur eine Instanz davon geben, die eben alles 
auf die Empfänger verteilt (falls ich dein Konzept richtig verstanden 
habe).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.