Autor Beitrag
JohnDyr
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Do 06.09.18 11:12 
Moin,

ich bin grade dabei eine Anwendung zu realisieren, welche eine Seitenleiste hat mit mehreren Knöpfen und ein Hauptfenster rechts daneben.

Skizze:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
------------------------------
|.Btn1.|.....................|
|------|.....................|
|.Btn2.|.....Hauptfenster....|
|------|.....................|
|.Btn3.|.....................|
------------------------------

Bei der Umsetzung habe ich für das Hauptfenster mehrere überlappende Panels verwendet, welche abhängig vom Btn.Click das Attribut Visibility ändern. Z.B. Btn1.Click -> Panel1.Visible = true; Panel2.Visibilty = false; Panel3.Visibilty = false; etc.

Das funktioniert zwar, allerdings Frage ich mich ob dies die beste Möglichkeit ist. Die Entwicklung bei Anwendung dieses Vorgehens ist ab und an mühselig und etwas hackelig. Vielleicht liegt das daran, dass ich aktuell 6 überlappende Panels habe, wobei das ja eigentlich nicht besonders viel ist...

Lange Rede kurzer Sinn: Würdet ihr das auch so machen?

Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 06.09.18 13:24 
Hallo und :welcome:

ich würde dir raten, für die Panels eigenständige Benutzersteuerelemente (UserControls) zu verwenden, da du diese dann getrennt im Designer bearbeiten kannst. So überfrachtest du auch nicht das Hauptformular mit Aberdutzenden von Komponenten. Desweiteren hast du eine bessere Kapselung und kannst eine einheitliche Schnittstelle dazu anbieten.
Und im Hauptformular (bzw. ich würde daraus dann auch ein UserControl erzeugen und dieses dann im Hauptformular verwenden), würde ich einfach eine List<UserControl> (oder explizit List<IMyUserControl>) als Schnittstelle anbieten, so daß die Buttons dann dynamisch generiert werden und das passende UserControl dann bei Klick angezeigt wird.

Für diesen Beitrag haben gedankt: JohnDyr
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Do 06.09.18 13:58 
Danke für den Tipp mit den UserControls. Ich bin mit VisualStudio noch nicht so firm und kenne mich mit den ganzen einzelnen Designelementen noch nicht so gut aus. Ich werde mein Glück damit probieren, komme aber bei Fragen nochmal ggf. zurück aufs Forum.

Danke soweit :-)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 06.09.18 14:18 
Noch ein Tipp:
Wenn du ein UserControl erstellt hast, kannst du im Designer per Copy&Paste (bzw. Cut&Paste) die untergeordneten Panel-Elemente (aus deinem bisherigen Hauptformular) in das UserControl kopieren (bzw. verschieben). So brauchst du dann diese nicht wieder neu erzeugen. Falls du schon Code für einzelne Elemente geschrieben hast (z.B. Initialisierung, Ereignismethoden, ...), so mußt du diese dann ebenfalls herüberkopieren.

Für diesen Beitrag haben gedankt: JohnDyr
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Fr 12.10.18 10:44 
Das funktioniert wunderbar, habe es eben umgesetzt! Danke vielmals :)

Für diesen Beitrag haben gedankt: Th69
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: So 25.11.18 21:38 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Noch ein Tipp:
Wenn du ein UserControl erstellt hast, kannst du im Designer per Copy&Paste (bzw. Cut&Paste) die untergeordneten Panel-Elemente (aus deinem bisherigen Hauptformular) in das UserControl kopieren (bzw. verschieben). So brauchst du dann diese nicht wieder neu erzeugen. Falls du schon Code für einzelne Elemente geschrieben hast (z.B. Initialisierung, Ereignismethoden, ...), so mußt du diese dann ebenfalls herüberkopieren.


Hi,

ich habe nun leider doch ein Problem mit den UCs. Wie gehe ich am besten vor, wenn ich aus einem User Control heraus ein anderes aufrufen möchte? Angenommen ich habe UC A und dort ist ein Button, welcher UC A schließen und UC B aufrufen soll. Stehe da etwas auf dem Schlauch :(
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 26.11.18 10:31 
Das ist ein typisches Problem, zu dem ich auch einen Artikel verfasst habe: Kommunikation von 2 Forms (gilt aber allgemein für Klassen, also auch UserControls).

UserControls sind trotzdem aber keine Forms, so daß diese nicht geschlossen werden können (höchstens auf der Form versteckt).
Willst du also von einem UserControl zu einem anderen UserControl in deiner Anwendung wechseln, so solltest du ein Ereignis (event) bereitstellen, welches dann von der Hauptform abonniert wird (da dieses ja die Liste aller UserControls enthält) und das führt dann den Wechsel durch (analog zum Button-Klick) - in meinem Artikel unter "Lösung: Verwendung von Eigenschaften (Properties) und Ereignissen (Events) / 2. Ereignisse" zu finden.

Für diesen Beitrag haben gedankt: JohnDyr
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Mo 26.11.18 11:07 
Besten Dank, ich lese mir den Artikel gleich durch :-)

VG,
JohnDyr

Edit:

Ziemlich gut erklärt! Werde das später Zuhause direkt mal ausprobieren. Thx :)
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Mo 26.11.18 20:16 
Ich habe nun leider doch Schwierigkeiten es umzusetzen. Deshalb versuche ich es hier nochmal...

Nochmal zum Sachverhalt: Mein Programm hat links eines Sidebar, und rechts ein Panel "Master", wo die UserControls angezeigt werden.

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
---------------------------------------
|.BtnOrders......|.....................|
|----------------|.....................|
|.BtnCreateOrder.|.....PnlMaster.......|
|----------------|.....................|
---------------------------------------


Bei Klick auf BtnOrders wird folgender Code ausgeführt:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
private void BtnOrders_Click(object sender, EventArgs e)
{
  if (!PnlMaster.Controls.Contains(UcOrders.Instance))
  {
    PnlMaster.Controls.Add(UcOrders.Instance);
    UcOrders.Instance.Dock = DockStyle.Fill;
    UcOrders.Instance.BringToFront();
  }
  else
    UcOrders.Instance.BringToFront();
}


Bei Klick auf BtnCreateOrder wird analog dazu, jedoch mit einer anderen UserControl (UcCreateOrder), diese geöffnet. Innerhalb von UcOrders habe ich ein Button 1. Auf Klick dessen möchte ich, dass sich das UcCreateOrder öffnet. Dem Tutorial zufolge müsste dies ja dann so geschehen, dass aus dem UcOrders heraus ein Event an die Main Form gefeuert wird. Dieses Event muss dazu führen, dass sich UcCreateOrder öffnet. Im Prinzip kann ich also sagen, sobald ich in der Main Form bin, öffne die Form mit derselben Logik wie bei einem Button Click.

Folgende Logik habe ich in UcOrder implementiert:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
public event EventHandler OpenCreateOrder; // Ereignis deklarieren

protected virtual void OnOpenCreateOrder(EventArgs e)
{
  EventHandler ev = OpenCreateOrder;
  if (ev != null)
    ev(this, e); // abonnierte Ereignismethode(n) aufrufen
}

private void button1_Click(object sender, EventArgs e)
{
  OnOpenCreateOrder(e);
}


Jetzt fehlt mir noch die Logik, dass die Main Form dieses Event was in UcOrder getriggert wird, abonnieren muss. Dementsprechend versuche ich etwas wie...

ausblenden Quelltext
1:
2:
3:
4:
5:
public FrmMain()
{
  InitializeComponent();
        ucOrders.OpenCreateOrder += XYZ; // wenn das Event OpenCreateOrder gefeuert wird, führe BtnCreateOrder_Click aus.
}


Auf das XYZ komme ich nicht... wie muss ich das Umsetzen? Stehe total auf dem Schlauch gerade :( :(

Bin für jede Hilfe dankbar.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 26.11.18 20:32 
Sobald du in Visual Studio das += für den Delegaten getippt hast einfach mal auf den Tooltip warten und machen was in dem Tooltip steht ;) Hint: TAB klicken
Dann bekommst du automatisch die passende Methode generiert die du nutzen kannst.
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Mo 26.11.18 20:50 
Nun, ich habe dadurch ein Vorschlag bekommen und diesen implementiert. Der Code lässt sich auch kompilieren und ausführen. Beim klick auf den button1 in UcOrders passiert allerdings nichts :(

Folgenden Code habe ich bisher implementiert:

UcOrder.cs

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
public event EventHandler<EventArgs> OpenCreateOrder; // Ereignis deklarieren

protected virtual void OnOpenCreateOrder(EventArgs e)
{
  EventHandler<EventArgs> ev = OpenCreateOrder;
  if (ev != null)
    ev(this, e); // abonnierte Ereignismethode(n) aufrufen
}

private void button1_Click(object sender, EventArgs e)
{
  OnOpenCreateOrder(e);
}


FrmMain.cs
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
public FrmMain()
{
  InitializeComponent();
  UcOrders ucOrders = new UcOrders();
  ucOrders.OpenCreateOrder += UcOrders_OpenCreateOrder;
}

private void UcOrders_OpenCreateOrder(object sender, EventArgs e)
{
  if (!PnlMaster.Controls.Contains(UcCreateOrder.Instance))
  {
    PnlMaster.Controls.Add(UcCreateOrder.Instance);
    UcCreateOrder.Instance.Dock = DockStyle.Fill;
    UcCreateOrder.Instance.BringToFront();
  }
  else
    UcCreateOrder.Instance.BringToFront();
}


Moderiert von user profile iconTh69: Vollzitat entfernt.
Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 26.11.18 21:08 
Wie ist die Instance-Property implementiert?

Moderiert von user profile iconTh69: C#-Tags hinzugefügt

Für diesen Beitrag haben gedankt: JohnDyr
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 27.11.18 09:38 
Und setze mal einen Haltepunkt (breakpoint) auf die erste Zeile von UcOrders_OpenCreateOrder(...). Dann wirst du sehen, daß das Programm dort gar nicht hinkommt.

Du legst in dem Form-Konstruktor eine lokale Variable vom Typ UcOrders an, diese ist aber nicht dieselbe Instanz mit der du über den Button das UserControl anzeigst.
Ich denke, dann sollte es wohl so aussehen:
ausblenden C#-Quelltext
1:
UcOrders.Instance.OpenCreateOrder += UcOrders_OpenCreateOrder;					

Ich (und auch viele andere Entwickler) halten allerdings nichts vom Singleton-Pattern (und sehen es eher als Anti-Pattern: zu viele Nachteile).

Ich würde einfach Membervariablen für die verschiedenen UserControls in der Form-Klasse anlegen (außerdem in eine Liste einfügen, wie in meinem ersten Beitrag erklärt) und diese dann benutzen.

Für diesen Beitrag haben gedankt: JohnDyr
JohnDyr Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 10
C# (VS 2017)
BeitragVerfasst: Di 27.11.18 11:16 
@Th69, du hast absolut recht... Danke vielmals. Habe es nun gefixed und es funktioniert. Auch durch setzen des Breakpoints war es nachvollziehbar. Zum Thema Singleton Pattern: Ich werde nochmal überlegen ob ich es tatsächlich nochmal Refactore. Ich denke hierzu gibt es viele Vorteile als auch Nachteile. Ungern möchte ich hierzu eine Diskussion entfachen, da es ja ursprünglich um was anderes ging. Vielleicht aber in einem anderen Thread :-)

Zitat:
Wie ist die Instance-Property implementiert?


Der Vollständigkeit halber nochmal die Implementierung der Instance:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
public static Uc1 Instance
{
  get
  {
    if (_instance == null)
      _instance = new Uc1 ();
    return _instance;
  }
}


Jedenfalls funktioniert es jetzt. Danke nochmal für eure Hilfe!!!