Autor |
Beitrag |
JohnDyr
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: 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:
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
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 06.09.18 13:24
Hallo und
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
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: 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
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: 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
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: Fr 12.10.18 10:44
Das funktioniert wunderbar, habe es eben umgesetzt! Danke vielmals
Für diesen Beitrag haben gedankt: Th69
|
|
JohnDyr
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: 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
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: 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
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: 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
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: 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
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: 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
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: Mo 26.11.18 20:50
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mo 26.11.18 21:08
Wie ist die Instance-Property implementiert?
Moderiert von Th69: C#-Tags hinzugefügt
Für diesen Beitrag haben gedankt: JohnDyr
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: 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 (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
Beiträge: 56
Erhaltene Danke: 1
Win 10
C# (VS 2017)
|
Verfasst: 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!!!
|
|