Laden...

Objekt erstellen in anderen Klasse

Erstellt von Xargus vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.659 Views
X
Xargus Themenstarter:in
9 Beiträge seit 2019
vor 4 Jahren
Objekt erstellen in anderen Klasse

Hallo Leute,

ich ein Problem beim auslagern diverser Sachen aus der Form1.cs in eine andere cs. ICh möchte zur Lauzeit mein Menu aus der DB laden und deswegen lege ich dynamisch Panel und andere Objekt an. Nun ist das recht viel und ich möchte es in eine extra Klasse (Class2.cs) auslagern.


using System;
using System.Windows.Forms;

namespace WindowsFormsApp11
{
  public partial class Form1 : Form
  {
    public Form1() { InitializeComponent(); }

    public static Form1 Instance { get { if (_Instance == null) _Instance = new Form1(); return _Instance; } }
    private static Form1 _Instance = null;

    private void Form1_Load(object sender, EventArgs e)
    {
      Class2.Instance.Erstelle_Panel();
    }
  }
  public partial class Class2
  {
    public static Class2 Instance { get { if (_Instance == null ) _Instance = new Class2(); return _Instance; } }
    private static Class2 _Instance = null;

    public void Erstelle_Panel()
    {
      Panel HP = (Panel)Form1.Instance.panelHaupt;
      Panel p = new Panel();
      p.Name = "Panel";
      p.Top = 10;
      p.Left = 0;
      p.Width = HP.Width;
      p.Height = 20;
      p.BackColor = System.Drawing.Color.Red;
      p.Parent = HP;
      p.Visible = true;
      p.Show();
    }
  }
}

Dabei fällt mir auf, dass in der drittletzen Zeile "p.Parent" einfach p.visible auf false gesetzt wird. Und in der vorletzten Zeile wird visible = true einfach ignoriert.

Wer kann mir helfen, den Fehler zu beheben?
Danke schon mal im Voraus.

Xargus

16.807 Beiträge seit 2008
vor 4 Jahren

"einfach so" über Magie passiert nichts im Code.
Warum Visible also false sein soll, das ergibt sich hier im Code nicht.

Code wird auch niemals "einfach so" ignoriert.
Schau Dir also das Verhalten im Debugger an.
[Artikel] Debugger: Wie verwende ich den von Visual Studio?

PS: eine saubere Singleton Implementierung macht man i.d.R. über die Lazy<T> Klasse.

5.657 Beiträge seit 2006
vor 4 Jahren

ICh möchte zur Lauzeit mein Menu aus der DB laden und deswegen lege ich dynamisch Panel und andere Objekt an.

Genau für solche Zwecke bietet sich DataBinding geradezu an. Dann könntest du dir das manuelle Erstellen und Positionieren im Code ersparen.

Du fügst das neu erstellte Panel übrigens nirgendwo hinzu, daher kann es auch nicht angezeigt werden.

Zwei Klassen als Singleton zu definieren, damit sie miteinander kommunizieren, ist nicht die richtige Herangehensweise. Siehe dazu: [FAQ] Kommunikation von 2 Forms

Es gibt übrigens für Windows Forms ein eigenes Unterforum, ich habe den Beitrag dorthin verschoben.

Weeks of programming can save you hours of planning

X
Xargus Themenstarter:in
9 Beiträge seit 2019
vor 4 Jahren

Hallo Danke für die Antworten.

Ich verstehe das

"Du fügst das neu erstellte Panel übrigens nirgendwo hinzu, daher kann es auch nicht angezeigt werden."

nicht.
Ich gebe doch den Parent an. und das ist das Hauptpanel in der Form1.

Wie kann ich das denn beheben?
Könntest du mir da ein Code-Beispiel geben oder noch besser, meinen Code korrigieren?

Danke Xargus

16.807 Beiträge seit 2008
vor 4 Jahren
X
Xargus Themenstarter:in
9 Beiträge seit 2019
vor 4 Jahren

hi,

lasse ich ein Singleton weg, weiss er in Klasse2 nicht die width und das parent-object.
wenn ich durchstepe zeigt er mir das Panel ja an in der control-liste. auch wenn ich es über databindings mache. aber angezeigt wird es trotzdem nicht.

vielleicht reden wir ja an einander vorbei. Vielleicht wäre ein änderung an meinem Code hilfreich.zumindest wenn ihr ihn hier postet, so dass ich ihn sehen kann.

hab die Links durchgelesen und das meiste davon ist meckern oder kritisieren oder irgendwelche wörter in den raum geschmissen mit dennen niemand (ausser ihr) was anfangen könnt. Oder ihr streitet euch darüber ob das Sinn macht oder nicht.

Mal ein richtige Codebespiel wäre echt toll.
Danke im Voraus

16.807 Beiträge seit 2008
vor 4 Jahren

Naja, wir schreiben Dir jetzt nicht Deinen Code. Das Sinn eines Forums ist die Hilfe zur Selbsthilfe.
Das heisst, wir geben Dir Hilfestellung, damit Du verstehst, woran das Problem liegt, es selbst identifizieren und selbst lösen kannst.

Dein Code hat eben zwei Defizite: das Singleton, das in der Form nicht notwendig ist.
Und dass Du das Control nicht über Add() hinzufügt. Mir zumindest wäre neu, dass das über das Parent geht.
Weiß auch nicht, woher Du das hast - die Doku zeigt das nicht.

lasse ich ein Singleton weg, weiss er in Klasse2 nicht die width und das parent-object.

Du wendest den Singleton auch missbräuchlich an. Ein Singleton hat einen ganz anderen Zweck.

In [FAQ] Kommunikation von 2 Forms (direkt in diesem Thema) ist beschrieben, wie sich zwei Forms kennen sollen.
In Zugriff auf Steuerelement aus Klasse [ink. Codebeispiel für die Kommunikation zwischen zwei Forms] gibt es Beispielcode.
Bisher hat dieses Thema tausenden Leuten erfolgreich geholfen.

Damit kannst Du 1:1 den Singleton ersetzen.

X
Xargus Themenstarter:in
9 Beiträge seit 2019
vor 4 Jahren

hi Abt,

ich lasse jetzt den einen Singleton weg. übergebe das gewünschte Panel direkt mit.
Adde das neue Panel und es wird trotzdem nicht angezeigt.


    public Panel p = new Panel();
    public void Erstelle_Panel(Panel HP)
    {
      HP.Controls.Add(p);
      p.Name = "Panel";
    }

Wenn ich mir die Links anschaue dann lese ich immer nur event und Komunikation zweier Forms. Das brauche ich doch garnicht.

ich möchte lediglich Panels erstellen und diese in eine andere *.cs auslagern.

erstelle ich die Panels in der Form1.cs dann geht das wunderbar. Nur möchte ich die ganze Menu-Erstellung und deren Funktionalitäten der Übersicht halber auslagern.

5.657 Beiträge seit 2006
vor 4 Jahren

Ich verstehe wirklich nicht, worüber du dich beschwerst. Es ist doch alles in dem verlinkten Artikel erklärt. Da geht es auch ohne Singletons. Das ganze nennt sich Objektorientierte Programmierung, und wenn man einen Begriff noch nicht gehört hat, kann man auch mal bei Google nachschlagen.

Mit deiner Herangehensweise wirst du auf Dauer immer wieder frustriert sein, und auch kaum Hilfe von anderen bekommen können, einfach weil keiner so entwickelt.

Zu deiner letzten Frage: Hast du das Haupt-Panel denn auch dem Fenster hinzugefügt?

Weeks of programming can save you hours of planning

16.807 Beiträge seit 2008
vor 4 Jahren

ich möchte lediglich Panels erstellen und diese in eine andere *.cs auslagern.

Was Du da baust ist die bidirektionale Kommunikation von zwei Klassen.
Ob das Forms sind oder nicht: das Beispiel gilt trotzdem.

Willst Du keine Kommunikation, was Dein Code suggeriert und evtl. zu Verwirrung beigetragen hat, dann musst Du nochmal komplett mit den OOP Basics beginnen.

Dein Code sieht nämlich aus, dass Du Form1 inhaltlich kopiert hast und Class2 draus gemacht hast.
Hat aber nichts von Auslagern zutun.

In Forms werden dazu gerne Factories verwendet, damit UI Elemente zentral erzeugt werden.
Trotzdem müsstest Du Dich um das Erstellen von Controls nicht kümmern, wenn Du Binding verwenden würdest.
In WinForms ist das generell empfohlen; in WPF wirst Du dazu gezwungen (und das ist gut so).

namespace WindowsFormsApp11
{
  public partial class Form1 : Form
  {
    private PanelFactory _panelFactory;

    public Form1() {
        _panelFactory = new PanelFactory();
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        var panel = _panelFactory.Create();
        this.Controls.Add(panel);
    }
  }
  
  public class PanelFactory
  {
    public Panel Create()
    {
      Panel p = new Panel();
      p.Name = "Panel";
      p.Top = 10;
      p.Left = 0;
      p.Height = 20;
      p.BackColor = System.Drawing.Color.Red;
      p.Show();

      return p;
    }
  }
}
4.931 Beiträge seit 2008
vor 4 Jahren

Nur zur Info:

Und dass Du das Control nicht über Add() hinzufügt. Mir zumindest wäre neu, dass das über das Parent geht.
Weiß auch nicht, woher Du das hast - die Doku zeigt das nicht.

Das ist aber intern ein und dasselbe (in der WinAPI gibt es nur die Funktion SetParent dafür).
Im .NET-Code wird dafür beim Setzen von Parent Controls.Add aufgerufen (bzw. Controls.Remove wenn null zugewiesen wird):


public Control Parent
{
    get
    {
        IntSecurity.GetParent.Demand();
        return this.ParentInternal;
    }
    set
    {
        this.ParentInternal = value;
    }
}

internal virtual Control ParentInternal
{
    get
    {
        return this.parent;
    }
    set
    {
        if (this.parent != value)
        {
            if (value != null)
            {
                value.Controls.Add(this);
            }
            else
            {
                this.parent.Controls.Remove(this);
            }
        }
    }
}

Und Add ruft intern SetParentHandle auf, welches dann schließlich die WinAPI-Funktion aufruft:


UnsafeNativeMethods.SetParent(new HandleRef(this.window, this.Handle), new HandleRef(null, value));

PS: Und im Code von Xargus sind auch folgende beiden Zeilen äquivalent:


p.Visible = true;
p.Show();

Das Tückische beim Auslesen von Visible ist, daß man jedesmal false erhält, solange das Control noch nicht wirklich angezeigt wurde (d.h. vor FormShown, also eben auch z.B. im Form.Load):


public bool Visible
{
    get
    {
        return this.GetVisibleCore();
     }
     set
     {
        this.SetVisibleCore(value);
     }
}

internal const int STATE_VISIBLE = 2;

internal virtual bool GetVisibleCore()
{
    if (!this.GetState(2)) // <- per Reflection erhalten (eigentlich im Code steht STATE_VISIBLE)
    {
        return false;
    }
    return ((this.ParentInternal == null) || this.ParentInternal.GetVisibleCore());
}

X
Xargus Themenstarter:in
9 Beiträge seit 2019
vor 4 Jahren

Hallo,

und danke für die Antworten.

Abt so ähnlich hatte ich es erst auch. Aus irgend einen Grund (sicher lag er zwischen MEINEN Ohren) ging es nicht und ich habe angefangen, hier rum zu stöbern. Dabei bin ich ja erst auf die SingleTon´s gestossen und habe diese versucht bei mir einzubauen.

Nach ein paar Stunden Links studieren und 5 hergehauenen Wörtern von euch, wars dann ganz aus und ich hab überhaupt nix mehr kapiert. Ich habs leider nicht so mit Fachbegriffen. Bin halt auch nicht studiert.... 😦

Nun hab ich es noch einmal von Grund auf neu gemacht und dein Beispiel auf meinen Code umgemünzt. Und nun geht das auch so wie ich es wollte.

Danke euch
Grüsse Xargus

4.931 Beiträge seit 2008
vor 4 Jahren

Noch etwas:

In Forms werden dazu gerne Factories verwendet, damit UI Elemente zentral erzeugt werden.
Trotzdem müsstest Du Dich um das Erstellen von Controls nicht kümmern, wenn Du Binding verwenden würdest.
In WinForms ist das generell empfohlen; in WPF wirst Du dazu gezwungen (und das ist gut so).

Mit WinForms kann man nur "DataBinding" durchführen (also nur Daten an bestehende Controls binden), keine "Control Templates" (o.ä.), d.h. man muß selber Code (wie z.B. über so eine Factory) schreiben, um Controls zu erzeugen.

Und "gezwungen" halte ich auch für etwas übertrieben, aber es sollte so gemacht werden (bzw. es wird insbesondere mit MVVM so empfohlen: [Artikel] MVVM und DataBinding).