Laden...

Zugriff auf Steuerelement aus Klasse [ink. Codebeispiel für die Kommunikation zwischen zwei Forms]

Erstellt von Flite vor 18 Jahren Letzter Beitrag vor 18 Jahren 45.310 Views
Information von herbivore vor 18 Jahren

Dies ist ein Thread, auf den aus der FAQ ([FAQ] Kommunikation von 2 Forms) verwiesen wird. Bitte keine weitere Diskussion, sondern nur wichtige Ergänzungen und diese bitte knapp und präzise. Vielen Dank!

F
Flite Themenstarter:in
22 Beiträge seit 2005
vor 18 Jahren
Zugriff auf Steuerelement aus Klasse [ink. Codebeispiel für die Kommunikation zwischen zwei Forms]

Hallo!

Ich habe eine Funktion in einer Klasse und möchte von dieser Funktion aus auf ein Steuerelement einer Form zugreifen.

Mit Form1. erhalte ich die Steuerelemente nicht (ist ja auch richtig - bei Form1 handelt es sich ja um die Klasse selbst, nicht um die Instanz). Aber wie kann ich auf die Instanz der Form zugreifen und ein Steuerelement verändern?

Viele Grüße & Danke!
Flite

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Flite,

du solltest von außen nie auf die Steuerelemente einer Form zugreifen! Ist deine Klasse, von der der Zugriff erfolgen soll, selbst ein Form? Dann schau mal in Kommunikation von 2 Forms . Wenn nicht, scheib mal, was du eigentlich machen/erreichen willst.

herbivore

F
Flite Themenstarter:in
22 Beiträge seit 2005
vor 18 Jahren

Hallo herbivore,

danke für deine Antwort.

Wie du vielleicht gemerkt hast, programmiere ich noch nicht lange in C#. Zwar habe ich bereits Jahre in C++ und Visual Basic und Delphi programmiert, aber C# ist mir noch recht unbekannt.

Ich habe folgendes vor:
Ich habe vier Klassen (cPROJECT, cSEQUENCE, cDEVICE, cPOINT). Ich will in jede dieser Klassen eine ArrayList mit der untergeordneten Klasse erzeugen. Also jedes Projekt soll mehrere Sequenzen haben, jede Sequenz mehrere Geräte und jedes Gerät mehrere Punkte.

Wenn ich nun dynamisch durch eine Funktion zu einer Sequenz ein Gerät hinzufüge, möchte ich, dass automatisch in einer Listbox auch das neuhinzugefügte Element reinkommt. Das wollte ich eigentlich nciht in den Button schreiben, sondern in die Funktion der Klasse, so dass das automatisch funktioniert.

Klar - in den Button kann ich die Routine auch reinschreiben. Aber dann muss diese auch in jeden Button rein, was zusätzlich Code verursacht.

Eine andere Frage noch. Wie kann ich eine zweite Form anzeigen lassen?!

Viele Grüße
Flite

F
Flite Themenstarter:in
22 Beiträge seit 2005
vor 18 Jahren

Das mit der zweiten Form hab ich grade rausgekriegt 🙂

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Flite,

das mit den Klassen cPROJECT, cSEQUENCE, cDEVICE, cPOINT geht klar, auch wenn die nach C#-Namenskonventionen Project, Sequence, Device und Point heißen sollten.

Wenn eine Objekt geändert wird, sollte es einen (eigenen) Event feuern, um die Änderung der Außenwelt mitzuteilen (ohne dass es die Außenwelt dazu kennen muss!).

Das Form, das das Objekt anzeigt, registriert einen EventHandler für diesen Event und kann dann darin selbst die nötige Aktualisierung der Oberfläche vornehmen. Quasi eine Abart des Observer-Pattern.

herbivore

F
Flite Themenstarter:in
22 Beiträge seit 2005
vor 18 Jahren

Hallo herbivore,

danke für die Antwort.

Ich werde versuchen, das Ganze so hinzukriegen. Wenn ich noch Fragen habe, komme ich wieder auf dich zurück 🙂

Vielen Dank nochmal!

Liebe Grüße
Flite

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Flite,

zur Ergänzung des Gesagten, als Grundsatz/Verallgemeinerung vielleicht noch:

Man sollte Klassen immer (maximal) entkoppeln. Wenn Klasse A die Klasse B kennt/benutzt, dann sollte B nicht Klasse A kennen/benutzt. Sonst kann ich B nur aus A benutzen und B ist nicht mehr wiederverwendbar.

Wenn man Oberflächenklassen (Form) und Modellklassen (Project, Sequence, ...) hat, sollten die Oberflächenklassen die Modellklassen kennen, aber nicht umgekehrt. Sonst kann man z.B. die Oberfläche später nicht austauschen (wenn man z.B. von Windows-Forms auf eine Web-Oberfläche umstellen will).

Auch bei Forms untereinander: Wenn Form1 Form2 kennt/benutzt, sollte Form2 nicht Form1 kennen.

Die ggf. doch nötige Rückkommunikation löst man durch Events (oder den Observer-Pattern).

herbivore

F
Flite Themenstarter:in
22 Beiträge seit 2005
vor 18 Jahren

Ok - kannst du vielleicht ein kleines Beispiel machen, wie das mit den Events fuinktioniert? Ich habe bisher noch nicht damit gearbeitet.

In der Klasse Sequence gibt es eine Funktion add_device(). In dieser Funktion wird zur ArrayList device ein neues Element hinzugefügt. Jetzt soll automatisch die Listbox aktualisiert werden.

Vielleicht kannst du mir auch eine Seite empfehlen, wo das Handling von Events und EventHandler beschrieben wird.

Viele Grüße
Flite

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Flite,

siehe [Lösung] Problem mit EventHandler.

herbivore

F
Flite Themenstarter:in
22 Beiträge seit 2005
vor 18 Jahren

Hallo herbivore,

super, danke! Ich bin grade am versuchen.

Hab ich das richtig verstanden. Wenn ich nun eine weitere Form als Dialog habe und hier z.B. die Daten für das neue Device eingebe und dann auf OK klicke, dann soll ein Event in der Hauptform aufgerufen werden, dass dann die entsprechenden Daten setzt?

Viele Grüße
Flite

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Flite,

dem Prinzip "Code sagt mehr als 1000 Worte" folgend mal ein Beispiel:


using System;
using System.Windows.Forms;
using System.Drawing;

public class Adresse
{
   public String Ort
   {
      get { return _strOrt; }
      set {
         if (_strOrt != value) {
            _strOrt = value;
            OnOrtChanged (EventArgs.Empty);
         }
      }
   }
   private String _strOrt;

   public event EventHandler OrtChanged;

   protected void OnOrtChanged (EventArgs ea)
   {
      if (OrtChanged != null) {
         OrtChanged (this, ea);
      }
   }
}

public class MyForm : Form
{
   protected const int iMargin = 10;
}

public class VersicherterFenster : MyForm
{
   private TextBox _tbxName;
   private TextBox _tbxOrt;
   private Button  _btnAdresse;
   private Adresse _adr;

   public VersicherterFenster ()
   {
      Control ctrlCurr;
      Control ctrlPrev;

      Text = "Versicherter";

      ctrlCurr = _tbxName = new TextBox ();
      ctrlCurr.Location = new Point (iMargin, iMargin);
      Controls.Add (ctrlCurr);
      ctrlPrev = ctrlCurr;

      ctrlCurr = _tbxOrt = new TextBox ();
      ctrlCurr.Location = new Point (iMargin, ctrlPrev.Bottom + iMargin);
      ((TextBox)ctrlCurr).ReadOnly = true;
      Controls.Add (ctrlCurr);
      ctrlPrev = ctrlCurr;

      ctrlCurr = _btnAdresse = new Button ();
      ctrlCurr.Location = new Point (iMargin, ctrlPrev.Bottom + iMargin);
      ctrlCurr.Width = ctrlPrev.Width;
      ctrlCurr.Text = "Adresse";
      ctrlCurr.Click += new EventHandler (AdresseClick);
      Controls.Add (ctrlCurr);
      ctrlPrev = ctrlCurr;

      AcceptButton = _btnAdresse;

      ClientSize = new Size (ctrlPrev.Right + iMargin,
                             ctrlPrev.Bottom + iMargin);

      _adr = new Adresse ();
      _adr.OrtChanged += new EventHandler (AdresseOrtChanged);

      // Beispieldaten
      _tbxName.Text = "herbivore";
      _adr.Ort = "Berlin";

   }

   protected void AdresseClick (Object objSender, EventArgs e)
   {
      AdresseFenster formAdresse = new AdresseFenster (_adr);
      formAdresse.Owner = this;
      formAdresse.Show ();
   }

   protected void AdresseOrtChanged (Object objSender, EventArgs e)
   {
      _tbxOrt.Text = ((Adresse)objSender).Ort;
   }
}

public class AdresseFenster : MyForm
{
   private TextBox _tbxOrt;
   private Button  _btnOk;

   Adresse _adr;

   public AdresseFenster (Adresse adr)
   {
      Control ctrlCurr;
      Control ctrlPrev;

      _adr = adr;

      Text = "Adresse";

      ctrlCurr = _tbxOrt = new TextBox ();
      ctrlCurr.Location = new Point (iMargin, iMargin);
      ctrlCurr.Text = _adr.Ort;
      Controls.Add (ctrlCurr);
      ctrlPrev = ctrlCurr;

      ctrlCurr = _btnOk = new Button ();
      ctrlCurr.Location = new Point (iMargin, ctrlPrev.Bottom + iMargin);
      ctrlCurr.Width = ctrlPrev.Width;
      ctrlCurr.Text = "OK";
      ctrlCurr.Click += new EventHandler (OkClick);
      Controls.Add (ctrlCurr);
      ctrlPrev = ctrlCurr;

      AcceptButton = _btnOk;

      ClientSize = new Size (ctrlPrev.Right + iMargin,
                             ctrlPrev.Bottom + iMargin);
   }

   protected void OkClick (Object objSender, EventArgs e)
   {
      _adr.Ort = _tbxOrt.Text;
      Close ();
   }
}

abstract class App
{
   public static void Main ()
   {
      Application.Run (new VersicherterFenster ());
   }
}

Kann sein, dass du es genau so gemeint hast.

herbivore

Suchhilfe: 1000 Worte

F
Flite Themenstarter:in
22 Beiträge seit 2005
vor 18 Jahren

Hallo herbivore,

soweit ich den Code jetzt geblickt habe, hab ich es gemeint. Funktionieren tut es inzwischen auch.

Vielen Dank nochmal für deine super Unterstützung!

Liebe Grüße
Flite