Announcement

Collapse
No announcement yet.

C# Form-Elemente in Klasse benutzen?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • C# Form-Elemente in Klasse benutzen?

    Hey,

    wie kann ich von einer externen Klasse (keine Form-Klasse) auf Form-Elemente einer Form-Klasse zugreifen, wie z.B auf die Textfelder?
    Ich habe nämlich eine Klasse erstellt, in der Datenbankoperationen ausgeführt werden aber
    naja, jetzt kann ich natürlich nicht so auf die Form-Elemente zugreifen. Ich prüfe dort z.B
    ob die Textbox leer ist und halt viele andere Sachen.

    Dabei handelt es sich aber schon um einige Elemente (20+).. wie geht man da vor?
    Zuletzt editiert von Threin; 01.03.2014, 00:49.

  • #2
    Hast Du die Form zusammengeklickt oder erzeugst Du diese dynamisch zur Laufzeit? Falls Du sie zusammengeklickt hast sollte diese eigentlich einen Name oder eine ID haben. Sowas wie TextBox1. Diese kannst Du dann im Code verwenden und mit .Text auf den Inhalt zugreifen.

    Comment


    • #3
      Naja, die grundsachen wie die Textboxen etc. habe ich schon mit dem Designer erstellt.
      Ich habe mich oben auch ein wenig schlecht ausgedrückt, von daher hier noch einmal, das was ich vorhabe.

      Ich habe eine neue Klasse im Projekt erstellt (keine Form-Klasse), von der aus will ich nun auf die Elemente der Form zugreifen.
      Es wird ja auch immer eine Klasse für die Form erstellt, in der kann ich ja auf die Elemente zugreifen aber nicht von meiner anderen (normalen) Klasse aus.

      Das macht man doch auch so, also Trennung von Logik und Design oder nicht?
      Naja, das ist wie gesagt das, was ich machen will.

      Comment


      • #4
        Das macht man doch auch so, also Trennung von Logik und Design oder nicht?
        Ja. Aber trennen heißt nicht (oder nicht nur) auf verschiedene Klassen zu verteilen sondern diese möglichst auch unabhängig voneinander zu machen.
        Aus der Logik direkt auf die UI zuzugreifen macht sie wohl kaum unabhängig voneinander. Du solltest dein Trennen damit beginnen von der Form auf die Logikklasse zuzugreifen aber auf keinen Fall umgekehrt.
        Wenn die Logikklasse Daten aus der Form benutzt so sammle diese auf der Form ein und übergebe sie an die Logikklasse aber lasse sie nicht von der Logiklasse aus der Form holen.

        Comment


        • #5
          Schau Dich mal etwas zum Thema Databinding, MVC und deren Varianten um. Da gehts eigentlich genau um das Problem was Du hast. Falls es Dir möglich ist kannst Du auch mal WPF ausprobieren. Dort ist diese Trennung etwas stärker im UI Framework integriert. In Windows Forms ist das natürlich auch möglich, allerdings ist da mehr manuelle Arbeit und Disziplin nötig und nicht wirklich vom Design des Frameworks vorgegeben.

          Comment


          • #6
            Originally posted by Ralf Jansen View Post
            Ja. Aber trennen heißt nicht (oder nicht nur) auf verschiedene Klassen zu verteilen sondern diese möglichst auch unabhängig voneinander zu machen.
            Aus der Logik direkt auf die UI zuzugreifen macht sie wohl kaum unabhängig voneinander. Du solltest dein Trennen damit beginnen von der Form auf die Logikklasse zuzugreifen aber auf keinen Fall umgekehrt.
            Wenn die Logikklasse Daten aus der Form benutzt so sammle diese auf der Form ein und übergebe sie an die Logikklasse aber lasse sie nicht von der Logiklasse aus der Form holen.
            Ja, das hatte ich ja vor.
            Ich wollte auch nicht direkt von der Logik auf die Form zugreifen, klang aber so wenn ich mir das durchlese.
            Damit war halt nur gemeint, dass ich die Daten dort brauche ..

            Wie würde man denn dann die Daten konkret übergeben, hast du da mal ein Beispiel?
            Ich brauche ja wie gesagt den Text von der Textbox oder eher gesagt den Textboxen, wenn auf einen Button geklickt wird.
            Diese müssen dann ja irgendwie an die Logik Klasse übergeben werden.

            Originally posted by fanderlf View Post
            Schau Dich mal etwas zum Thema Databinding, MVC und deren Varianten um. Da gehts eigentlich genau um das Problem was Du hast. Falls es Dir möglich ist kannst Du auch mal WPF ausprobieren. Dort ist diese Trennung etwas stärker im UI Framework integriert. In Windows Forms ist das natürlich auch möglich, allerdings ist da mehr manuelle Arbeit und Disziplin nötig und nicht wirklich vom Design des Frameworks vorgegeben.
            Naja, leider kann ich nicht auf WPF wechseln und ich habe mich auch eher wenig mit WPF beschäftigt.
            Das Prinzip davon kenne ich auch schon nur leider habe ich mich nur in PHP mit der richtigen Umsetzung beschäftigt.

            Comment


            • #7
              Wie würde man denn dann die Daten konkret übergeben, hast du da mal ein Beispiel?
              Die währen alle entweder zu banal (aka wenn du aus der Form die Logik aufrufst dann gib dem Methodenaufruf in der Logik doch die Daten mit) oder zu aufwendig um es hier mal kurz zu zeigen. Die hätten dann insbesondere auch rein gar nix mit dem zu tun was du jetzt vermutlich machst. Zeig doch einfach was du hast und wir zeigen wie man es in irgendeine Richtung weiterentwickeln kann bzw. wir können dann gleich sagen das es so zwecklos ist und du anders ansetzen solltest

              Comment


              • #8
                Originally posted by Ralf Jansen View Post
                Die währen alle entweder zu banal (aka wenn du aus der Form die Logik aufrufst dann gib dem Methodenaufruf in der Logik doch die Daten mit) oder zu aufwendig um es hier mal kurz zu zeigen. Die hätten dann insbesondere auch rein gar nix mit dem zu tun was du jetzt vermutlich machst. Zeig doch einfach was du hast und wir zeigen wie man es in irgendeine Richtung weiterentwickeln kann bzw. wir können dann gleich sagen das es so zwecklos ist und du anders ansetzen solltest
                Naja, ich will das ganze aber auch möglichst sauber machen.
                Ist das denn so gängig und sauber?

                Hier mal ein kleines Beispiel aber alles werde ich hier nicht posten.

                Code:
                public void AddEntry()
                {
                    string insert = "Insert into Eintrag(Vorname, Nachname, Strasse," +
                                    "Hausnummer,) values (" +
                                    "?Vorname, ?Nachname, ?Strasse, ?Hausnr);";
                
                    sql_con.ConnectionString = Data();
                
                    if (Textbox.firstName == "" || Textbox.lastName == "" ||)
                    {
                        MessageBox.Show("Die Pflichtfelder müssen ausgefüllt werden!", "Pflichtfelder",
                                         MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        return;
                    }
                    else
                    {
                        try
                        {
                            sql_con.Open();
                            sql_com.Connection = sql_con;
                            sql_com.CommandText = insert;
                            sql_com.Parameters.Add("?Vorname", MySqlDbType.VarChar).Value = TexBox_firstName.Text;
                            sql_com.Parameters.Add("?Nachname", MySqlDbType.VarChar).Value = TextBox_lastName.Text;
                
                            if (TextBox_Street.Text != "")
                            {
                                sql_comd.Parameters.Add("?Strasse", MySqlDbType.VarChar).Value = TextBbox_street.Text;
                            }
                            else { sql_com.Parameters.Add("?Strasse", MySqlDbType.VarChar).Value = null; }
                
                            if (TextBox_StreetNumber.Text != "") 
                            {
                                sql_com.Parameters.Add("?Strasse", MySqlDbType.VarChar).Value = TextBox_streetNumber.Text; 
                            }
                            else { sql_com.Parameters.Add("?Hausnr", MySqlDbType.VarChar).Value = null; }
                
                            sql_com.ExecuteNonQuery();
                        }
                        catch(Exception ex)
                        {
                            MessageBox.Show("Fehler!\n\n" + ex.Message, "Fehler!",
                                             MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                    sql_con.Close();
                }
                naja, ich weiß wohl das man den einen Teil oben noch mit in die Form Klasse reinnehmen könnte aber da drunter wird es ja schon schwieriger oder?
                Also denn Teil, wo man überprüft ob die Pflichtfelder überhaupt drin sind aber einige Felder sind halt optional.
                Das ist eine meiner Methoden in meiner Nicht-Form-Klasse.

                Bei einem Klick auf einen Button soll die Methode in der Nicht-Form-Klasse dann aufgerufen werden.

                Comment


                • #9
                  Mach doch public void AddEntry(string firstname, string lastname, string streetnumber)
                  Dann übergibt die Form alle Daten und AddEntry muß nicht auf die Form zugreifen. Abgesehen davon schreibst Du die Hausnummer in die Strasse und der Strassenname verschwindet dabei...
                  Und: Du initialisierst sql_con, überprüfst dann die Daten und machst ein return ohne sql_con wieder zu schließen...
                  Günther

                  Comment


                  • #10
                    Originally posted by Günther Weber View Post
                    Mach doch public void AddEntry(string firstname, string lastname, string streetnumber)
                    Dann übergibt die Form alle Daten und AddEntry muß nicht auf die Form zugreifen. Abgesehen davon schreibst Du die Hausnummer in die Strasse und der Strassenname verschwindet dabei...
                    Und: Du initialisierst sql_con, überprüfst dann die Daten und machst ein return ohne sql_con wieder zu schließen...
                    Ist das denn auch so ne saubere Methode?
                    Ich habe ja auch gesagt, das es ich dabei nicht um die komplette Methode handelt, geschweige denn der Klasse, die übrigens weitaus größer ist.
                    Es müssten dann 10 Daten + mit in der Paramterliste sein, ist das nicht ein bisschen krass?

                    Comment


                    • #11
                      Originally posted by Threin View Post
                      Ist das denn auch so ne saubere Methode?
                      Ich habe ja auch gesagt, das es ich dabei nicht um die komplette Methode handelt, geschweige denn der Klasse, die übrigens weitaus größer ist.
                      Es müssten dann 10 Daten + mit in der Paramterliste sein, ist das nicht ein bisschen krass?
                      Für so etwas baut man dann kleine Datencontainer (sehr oft entities genannt) aus reinen C# Objekten (POCO). Diese kann man wunderbar in der UI erzeugen und sie dann einer Schicht zum Speichern übergeben. Für Fälle in denen Daten geändert werden müssen bauen wir eigentlich fast immer spezielle Methoden aus denen am Ende ein ganz spezielles Update Statement für genau diesen einen Fall heraus fällt.

                      Auf jeden Fall würde ich Dir raten die Geschichte nicht direkt im UI/in der Form zu machen. Falls das natürlich jetzt funktioniert kannst Du es auch so stehen lassen. Architektur nur der Architektur Willen ist meistens fehl am Platz.

                      Comment


                      • #12
                        Es müssten dann 10 Daten + mit in der Paramterliste sein, ist das nicht ein bisschen krass?
                        Es ist eine Datenklasse die vielleicht 10 Properties hat. Das ist üblich.
                        In deinem Fall als Beispiel könnte das auch eine Komposition aus mehreren Klassen sein. Du hast da zum Beispiel ganz offensichtlich eine Person und eine Adresse.
                        Das es nachher wieder in einer Tabelle landet must dich ja nicht stören das in einem Model anders darzustellen.

                        Ist das denn so gängig und sauber?
                        Was mir als erstes auffällt das du das Logik nennst es aber Persistenz (speichern in eine Datenbank enthält) nennst und es hart mit einer visuellen Darstellungmethode (MessageBox) verknüpfst.
                        Wenn du es sauberer wilst dann solltest du das voneinander trennen.

                        a.) Du brauchst Klassen die deine Daten darstellen (nur Daten) und die du zum rumreichen zwischen den Beteiligten benutzt.
                        b.) sehe unterschiedliche Klassen für Logik (prüfen auf Vollständigkeit der Daten z.B.) und Persistenz (Speichern) vor. Die Logik führt ihre Logik dann auf die Datenklasse aus nicht auf die UI genauso wie die Persistenz Klasse die Datenklasse wegspeichern kann und nicht von der UI weiß. Beide werden also auf keinen Fall MessageBox oder ähnliches verwenden.
                        c.) Ablauf wäre dann bei einem Klick auf speichern in der UI.
                        - Sammeln der Daten in einer Datenklasse.
                        - Aufrufen einer Methode in der Logikschicht zum prüfen der Eingabe der man die Datenklasse übergibt
                        - wenn nicht ok dann Rückmeldung an den Aufrufer(die UI) damit die das visualisiert
                        - wenn ok dann Übergabe der Datenklasse an die Persistenzschicht die das wegspeichert
                        - wenn das nicht funktioniert entsprechende Rückgabe an den Aufrufer. Von da aus immer weiter an den Aufrufenden bis man in der UI schicht ankommt damit die dann visualisieren kann
                        Zuletzt editiert von Ralf Jansen; 07.03.2014, 10:47.

                        Comment


                        • #13
                          naja, wie gesagt ich kenne mich der Umsetzung eher wenig aus.
                          Das Problem ist jetzt nur, wie sammle ich die Daten denn dann konkret ein?
                          Das müsste dann ja beim Button Click die Klasse bzw. die Methode aufgerufen werden, die die Daten dann holt:

                          Also so oder so ähnlich?

                          Code:
                          private void button_AddEntry_Click(object sender, EventArgs e)
                          {
                              if(textBox_FirstName.Text == "" && textBox_LastName.Text == "")
                              {
                                  MessageBox.Show("Pflichtfelder ... !", "Pflichtfelder",
                                                      MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                                  return;
                              }
                              else
                              {
                                  FormData.Get();
                              }
                          }
                          Dann ne Struktur in einer neuen Klasse:

                          Code:
                          public class FormData
                          {
                              public struct Get
                              {
                                  string _firstName, _lastName;
                          
                                  public Get(string firstName, string lastName)
                                  {
                                      this._firstName = firstName;
                                      this._lastName = lastName;
                                  }
                              }
                          }
                          Der Text von der Textbox ist ja vom Typ String, von daher passt das ja oder?
                          Zudem frage ich mich jetzt auch, wie ich die Daten in die Struktur reinkriege, bzw. wie sammle ich diese in der Form ein und übergebe diese dann an die Struktur?
                          Dann nachher muss man diese Sachen ja auch jedes mal noch übergeben aber das Problem ist auch, das ich ja mehrere Formen haben, also eine zum speichern, eine zu m Löschen usw. und da heißen die Boxen dann auch gleich, muss man dann für alle eine eigene Struktur erstellen?
                          Kannst du mir da mal ein Beispiel geben?
                          Zuletzt editiert von Threin; 07.03.2014, 17:29.

                          Comment


                          • #14
                            Die benötigten Klassen

                            [HIGHLIGHT=C#]public class Entry
                            {
                            public string FirstName { get; set; }
                            public string LastName { get; set; }
                            }

                            public class EntryService
                            {
                            EntryPersistance persistance = new EntryPersistance();

                            public bool IsValid(Entry entry)
                            {
                            return (entry != null && !string.IsNullOrWhiteSpace(entry.FirstName) && !string.IsNullOrWhiteSpace(entry.LastName));
                            }

                            public bool AddEntry(Entry entry)
                            {
                            return (IsValid(entry) && persistance.Save(entry));
                            }
                            }

                            public class EntryPersistance
                            {
                            public bool Save(Entry entry)
                            {
                            // Datenbankzeugs
                            return true;
                            }
                            }[/HIGHLIGHT]

                            und deren Verwendung in der simpelsten Form.

                            [HIGHLIGHT=C#]private void button_AddEntry_Click(object sender, EventArgs e)
                            {
                            Entry entry = new Entry() { FirstName = textBox_FirstName.Text, LastName = textBox_LastName.Text }; // bei Verwendung von Databinding wäre eine Entry Instanz automatisch gefüllt
                            EntryService service = new EntryService(); // eine saubere Anwendungsarchtiketur würde bereits einen Service verwalten und man müßte denn hier nicht erzeugen sondern könnte in einfach verwenden

                            if (!service.AddEntry(entry))
                            {
                            // der einfachheithalber einfach eine boolesches Ergebnis. Sollte durch einen komplexen Result Typ ersetzt werden der eine ~genauere~ Beschreibung als ja/nein enthält.
                            MessageBox.Show(this, "Eintrag konnte nicht gespeichert werden.");
                            }
                            }[/HIGHLIGHT]

                            Comment


                            • #15
                              Hmm okay .. so sieht das dann also aus.
                              Das Beispiel hat mir echt geholfen, das ganze zu verstehen und ein paar Sachen hatte ich auch oben in deiner Antwort nicht verstanden.

                              Danke auf jeden Fall für das Beispiel und für die Zeit die du / ihr für mich opfert.

                              Noch einmal 4 Fragen dazu:

                              1. Also lagert man das alles komplett so weit wie möglich aus und auch die Überprüfung der Inhalte der Eingabefelder lagert man aus oder macht man das nur, wenn es nicht anders geht wie in meinem Fall?
                              Nur ist da jetzt auch noch ein Problem. Ich habe ja 4 Formklassen und da gibt es halt auch mal ein paar Sachen, die optional sind, also die null oder leer sein können Sollte man dafür dann noch mal eine eigene Methode in EntryService erstellen?

                              2. Muss man nicht eigentlich in dem ersten Codestück die Klasse Entry instanzieren oder wieso kennt der da die Propertys?

                              3. Also dürfen sich die Logikklassen gegenseitig kennen oder sollte man das auch da soweit wie möglich trennen?

                              4. Wie ist das mit dem komplexeren Rückgabewert gemeint? Wie geht man sowas eigentlich an, wenn man einen konkreteren Rückgabewert haben will und von welchem Typ sollte der Rückgabewert dann sein?
                              Ich glaube, es wird ja auch oft ein integer oder dergleichen verwendet oder? 1 wäre dann ok, 0 irgendeiner Fehler und -1 Exception?

                              Edit: Man würde das result doch aber in der Form verarbeiten, bzw. das muss man ja oder?
                              Weil sonst könnte man ja keine MessageBox oder dergleichen ausgeben?
                              Also z.B so ausgehend von einem int als Rückgabewert.

                              Code:
                              if (service.AddEntry(entry) == -1)
                              {
                                  MessageBox.Show(this, "Es ist ein Fehler aufgetreten!");   
                              }
                              if (service.AddEntry(entry) == -1)
                              {
                                  MessageBox.Show(this, "Der Eintrag konnte nicht gespeichert werden, weil er nicht den Vorgaben entspricht.");   
                              }
                              if (service.AddEntry(entry) == 1)
                              {
                                  MessageBox.Show(this, "Der Eintrag wurde erfolreich abgespeichert");   
                              }
                              Zuletzt editiert von Threin; 08.03.2014, 14:04. Reason: Fehler korrigiert / Ergänzung

                              Comment

                              Working...
                              X