Entwickler-Ecke
WinForms - Multiple Window Anwendung realisieren
JohnDyr - Do 06.09.18 11:12
Titel: Multiple Window Anwendung realisieren
Moin,
ich bin grade dabei eine Anwendung zu realisieren, welche eine Seitenleiste hat mit mehreren Knöpfen und ein Hauptfenster rechts daneben.
Skizze:
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 Th69: C#-Tags hinzugefügt
Th69 - 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.
JohnDyr - 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 - 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.
JohnDyr - Fr 12.10.18 10:44
Das funktioniert wunderbar, habe es eben umgesetzt! Danke vielmals :)
JohnDyr - So 25.11.18 21:38
Th69 hat folgendes geschrieben : |
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 - Mo 26.11.18 10:31
Das ist ein typisches Problem, zu dem ich auch einen Artikel verfasst habe:
Kommunikation von 2 Forms [
http://www.bitel.net/dghm1164/programming/Kommunikation_von_2_Forms.html] (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.
JohnDyr - 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 - 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.
Quelltext
1: 2: 3: 4: 5: 6:
| --------------------------------------- |.BtnOrders......|.....................| |----------------|.....................| |.BtnCreateOrder.|.....PnlMaster.......| |----------------|.....................| --------------------------------------- |
Bei Klick auf BtnOrders wird folgender Code ausgeführt:
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:
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...
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 - 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 - 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
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| public event EventHandler<EventArgs> OpenCreateOrder; protected virtual void OnOpenCreateOrder(EventArgs e) { EventHandler<EventArgs> ev = OpenCreateOrder; if (ev != null) ev(this, e); }
private void button1_Click(object sender, EventArgs e) { OnOpenCreateOrder(e); } |
FrmMain.cs
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 Th69: Vollzitat entfernt.
Moderiert von Th69: C#-Tags hinzugefügt
Ralf Jansen - Mo 26.11.18 21:08
Wie ist die
Instance-Property implementiert?
Moderiert von Th69: C#-Tags hinzugefügt
Th69 - 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:
C#-Quelltext
1:
| UcOrders.Instance.OpenCreateOrder += UcOrders_OpenCreateOrder; |
Ich (und auch viele andere Entwickler) halten allerdings nichts vom
Singleton-Pattern [
https://de.wikipedia.org/wiki/Singleton_(Entwurfsmuster)] (und sehen es eher als Anti-Pattern: zu viele
Nachteile [
https://de.wikipedia.org/wiki/Singleton_(Entwurfsmuster)#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.
JohnDyr - 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:
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!!!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!