Laden...
FAQ

[FAQ] Assistenten/Wizards: Mit Windows Forms eine Art Frameset einer Website nachbauen

Erstellt von herbivore vor 18 Jahren Letzter Beitrag vor 18 Jahren 34.055 Views
herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 18 Jahren
[FAQ] Assistenten/Wizards: Mit Windows Forms eine Art Frameset einer Website nachbauen

Hallo Community,

dieser Thread widmet sich der Frage, wie man ein Windows-Forms-Programm erstellen kann, bei dem das Fenster - wie bei einer Webseite möglich -, in mehrere "Frames" aufgeteilt ist. Dabei wird im linken Frame eine Navigationsleiste angezeigt und im Frame rechts daneben wird jeweils der zum gewählten Navigationspunkt gehörende Inhalt angezeigt. Außerdem gibt es noch einen dritten "Frame" am unteren Rand, als "globalen" Bereich, der immer angezeigt wird. Hier wird er für "OK" und "Abbrechen" verwendet.

Am Ende des Beitrags befinden sich zwei Screenshots, die das deutlicher machen, nach dem Motto, ein Bild sagt mehr als 1000 Worte. Die Farben und Rahmen der "Frames" sind natürlich nur dafür, dass man den Aufbau besser sieht und auch sieht, was passiert. Im fertigen Programm würde man Farben und Rahmen weglassen.

Die Antwort auf die Frage kommt in Form von Beispielcode, nach dem Motto, manchmal sagt auch Code mehr als 1000 Worte. Im Grunde läuft es darauf hinaus, dass sich die Inhalte auf mehreren hintereinanderliegenden Panels befinden und dass beim Wählen eines beliebigen Navigationspunkt das zugehörige Panel in den Vordergrund gebracht wird (und die anderen Inhalte verdeckt).

Natürlich kann man den Code in vielfacher Weise den eigenen Bedürfnissen anpassen. Hier ein paar Anregungen. Man kann ....

  • die Größe, Position und Anordnung der einzelnen Bereiche ändern,

  • Bereiche hinzufügen oder weglassen,

  • bei Assistenten den Navigationsbereich weglassen und den OK-Button durch Vor- und Zurück-Buttons ersetzen,

  • für die Navigation statt einer ListBox auch ein TreeView, eine Reihe von (Radio-)Buttons oder ein klickbares Bild oder Diagramm verwenden,

  • die Panels für die Inhalte (erst) bei Bedarf erzeugen und zerstören, insbesondere wenn man sehr viele verschiedene hat
    (ab ca. 100 Controls in einem Form kann es Performance-Probleme geben),

  • die Daten statt der Panels austauschen, insbesondere wenn man sehr viele gleichartige Panels hat, die sich nur in den Daten unterscheiden,

  • für die Inhalte statt der Panels auch UserControls verwenden (siehe nächsten Absatz)

  • und dergleichen mehr.

Das Beispiel wurde ohne Verwendung des VS-Designer erstellt. Wenn man den VS-Designer verwenden will, geht das auch. Dann sollte man statt Panels jedoch UserControls verwenden, weil man die sich gegenseitig verdeckenden Panels im Designer schlecht bearbeiten kann. UserControls kann man dagegen eigenständig bearbeiten ... und dann anschließend in das Zielfenster ziehen und übereinander legen. Wohlgemerkt übereinander (also alle auf gleicher Hierarchieebene, z.B. alle direkt im Form), nicht ineinander (also nicht ein UserControl in dem anderen).

Den Code kann man auch - leicht abgeändert - als Basis verwenden, um Assistenten oder Wizards zu realisieren.


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

//*****************************************************************************
public class MyWindow : Form
{
   const int iWidth            = 600;
   const int iHeight           = 480;
   const int iMargin           = 10;
   const int iNavigationWidth  = 200;
   const int iButtonWidth      = 80;
   const int iNumContentPanels = 3;

   private Panel    _pnlNavigation;
   private Panel [] _apnlContent = new Panel [iNumContentPanels];
   private Panel    _pnlButtons;

   private ListBox  _lbxNavigation;

   private Button   _pbOk;
   private Button   _pbCancel;

   //==========================================================================
   public MyWindow ()
   {
      Control  ctrlCurr;
      Control  ctrlPrev;
      Control  ctrlCurrContainer;

      Text = "Frames";
      ClientSize = new Size (iWidth, iHeight);
      MinimumSize = new Size (iNavigationWidth * 3 / 2, 150);

      //-----------------------------------------------------------------------
      // (Haupt-)Panels
      // (Die Reihenfolge des Hinzufügens ist wichtig!)
      //-----------------------------------------------------------------------

      //-----------------------------------------------------------------------
      ctrlCurrContainer = this;

      //-----------------------------------------------------------------------
      for (int i = 0; i < iNumContentPanels; ++i) {
         ctrlCurr = _apnlContent [i] = new Panel ();
         ((Panel)ctrlCurr).BorderStyle = BorderStyle.Fixed3D;
         ((Panel)ctrlCurr).BorderStyle = BorderStyle.FixedSingle;
         ctrlCurr.Dock = DockStyle.Fill;
         ctrlCurr.TabIndex = 2;
         ctrlPrev = ctrlCurr;
         ctrlCurrContainer.Controls.Add (ctrlCurr);
      }

      _apnlContent [0].BackColor = Color.Green;
      _apnlContent [1].BackColor = Color.Orange;
      _apnlContent [2].BackColor = Color.Yellow;

      //-----------------------------------------------------------------------
      ctrlCurr = _pnlNavigation = new Panel ();
      ctrlCurr.BackColor = Color.Red;
      ((Panel)ctrlCurr).BorderStyle = BorderStyle.Fixed3D;
      ((Panel)ctrlCurr).BorderStyle = BorderStyle.FixedSingle;
      ctrlCurr.Width = iNavigationWidth;
      ctrlCurr.Dock = DockStyle.Left;
      ctrlCurr.TabIndex = 1;
      ctrlPrev = ctrlCurr;
      ctrlCurrContainer.Controls.Add (ctrlCurr);

      //-----------------------------------------------------------------------
      ctrlCurr = _pnlButtons = new Panel ();
      ctrlCurr.BackColor = Color.Blue;
      ((Panel)ctrlCurr).BorderStyle = BorderStyle.Fixed3D;
      ((Panel)ctrlCurr).BorderStyle = BorderStyle.FixedSingle;
      ctrlCurr.Dock = DockStyle.Bottom;
      ctrlCurr.TabIndex = 3;
      ctrlPrev = ctrlCurr;
      ctrlCurrContainer.Controls.Add (ctrlCurr);


      //-----------------------------------------------------------------------
      // Inhalt von _pnlNavigation
      //-----------------------------------------------------------------------

      //-----------------------------------------------------------------------
      ctrlCurrContainer = _pnlNavigation;

      //-----------------------------------------------------------------------
      ctrlCurr = _lbxNavigation = new ListBox ();
      ctrlCurr.Location  = new Point (iMargin, iMargin);
      ((ListBox)ctrlCurr).IntegralHeight = false;

      ((ListBox)ctrlCurr).Items.Add ("Panel1");
      ((ListBox)ctrlCurr).Items.Add ("Panel2");
      ((ListBox)ctrlCurr).Items.Add ("Panel3");
      ctrlCurr.Size = new Size (ctrlCurrContainer.ClientSize.Width
                                - 2 * iMargin,
                                ctrlCurrContainer.ClientSize.Height
                                - 2 * iMargin);
      ctrlCurr.Anchor = AnchorStyles.Left
                      | AnchorStyles.Right
                      | AnchorStyles.Top
                      | AnchorStyles.Bottom;
      ((ListBox)ctrlCurr).SelectedIndexChanged
         += new EventHandler (NavigationSelectedIndexChanged);
      ctrlPrev = ctrlCurr;
      ctrlCurrContainer.Controls.Add (ctrlCurr);

      //-----------------------------------------------------------------------
      // Inhalt von _apnlContent [1..n]
      //-----------------------------------------------------------------------
      // ...

      //-----------------------------------------------------------------------
      // Inhalt von _pnlButtons
      //-----------------------------------------------------------------------

      //-----------------------------------------------------------------------
      ctrlCurrContainer = _pnlButtons;

      _pbOk = new Button ();
      _pnlButtons.Height = _pbOk.Height + (2 * iMargin)
                      + _pnlButtons.Height
                      - _pnlButtons.ClientSize.Height;

      //-----------------------------------------------------------------------
      ctrlCurr = _pbCancel = new Button ();
      ctrlCurr.Width = iButtonWidth;
      ctrlCurr.Location = new Point (ctrlCurrContainer.Width
                                     - ctrlCurr.Width
                                     - iMargin,
                                     iMargin);
      ctrlCurr.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
      ctrlCurr.Text = "Abbrechen";
      ctrlCurr.Click += new EventHandler (CancelClick);
      ctrlCurr.TabIndex = 2;
      ctrlPrev = ctrlCurr;
      ctrlCurrContainer.Controls.Add (ctrlCurr);

      //-----------------------------------------------------------------------
      ctrlCurr = _pbOk;
      ctrlCurr.Width = iButtonWidth;
      ctrlCurr.Location = new Point (ctrlPrev.Left - ctrlCurr.Width - iMargin,
                                     iMargin);
      ctrlCurr.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
      ctrlCurr.Text = "Ok";
      ctrlCurr.Click += new EventHandler (OkClick);
      ctrlCurr.TabIndex = 1;
      ctrlPrev = ctrlCurr;
      ctrlCurrContainer.Controls.Add (ctrlCurr);

      //-----------------------------------------------------------------------
      // Nacharbeiten
      //-----------------------------------------------------------------------
      AcceptButton = _pbOk;
      CancelButton = _pbCancel;

      _lbxNavigation.SelectedIndex = 0;
   }

   //==========================================================================
   protected void NavigationSelectedIndexChanged (Object objSender,
                                                  EventArgs ea)
   {
      ListBox lbxSender = (ListBox)objSender;

      if (lbxSender.SelectedIndex < 0) {
         // nichts zu tun
         return;
      }
      _apnlContent [lbxSender.SelectedIndex].BringToFront ();
   }

   //==========================================================================
   protected void OkClick (Object objSender, EventArgs ea)
   {
      //-----------------------------------------------------------------------
      // Speichen
      //-----------------------------------------------------------------------
      //...

      //-----------------------------------------------------------------------
      // Fenster schließen
      //-----------------------------------------------------------------------
      Close ();
   }


   //==========================================================================
   protected void CancelClick (Object objSender, EventArgs ea)
   {
      //-----------------------------------------------------------------------
      // Fenster schließen
      //-----------------------------------------------------------------------
      Close ();
   }
}

//*****************************************************************************
abstract class App
{
   public static void Main (string [] astrArg)
   {
      Application.Run (new MyWindow ());
   }
}

Den Code hatte ich ursprünglich in Mit Forms eine art Frame einer Website nachbauen? gepostet.

herbivore

PS: Von ErfinderDesRades gibt es einen alternativen Lösungsvorschlag in TabControl als Basis für Assistenten und sowas.

PPS: Von Tomot gibt es eine Komponente speziell für Einstellungsdialoge, die auf dem Frameprinzip basiert, siehe Einstellungsdialog (framesetlike).

PPPS: Von NeuroCoder gibt es eine Komponente zum Erstellen von Assistenten: WizardOfOz - Wizard Library für .NET 2.0