Laden...

Container control: Docking chaos der child controls!

Erstellt von citizen.ron vor 18 Jahren Letzter Beitrag vor 15 Jahren 10.164 Views
citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 18 Jahren
Container control: Docking chaos der child controls!

hi zusammen,

nachstehendes container user control habe ich zusammengebaut.

das problem ist, dass der container von sich aus per design einen header enthalten soll, der natürlich immer OBEN zu sehen sein soll -> DockStyle.Fill.

Sobald ich nun mein control benutze und ein control in ihm plaziere, wird es, wenn ich es nun ebenfalls mit DockStyle Fill anordne oberhalb des Headers angeordnet!!!

 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Casa.CCL
{
   [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
   public partial class RollupPanel : Panel
   {
      private Panel     _HeaderPanel;
      
      public RollupPanel()
      {
         //SuspendLayout();
         Dock = DockStyle.Top;

      // Create a HeaderPanel
         _HeaderPanel = new System.Windows.Forms.Panel();
         _HeaderPanel.BackColor = System.Drawing.Color.DarkSeaGreen;
         _HeaderPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
         _HeaderPanel.Dock = System.Windows.Forms.DockStyle.Top;
         _HeaderPanel.Location = new System.Drawing.Point(0, 0);
         _HeaderPanel.Name = "HeaderPanel";
         _HeaderPanel.Size = new System.Drawing.Size(258, 23);
         _HeaderPanel.TabIndex = 0;
         Controls.Add(this._HeaderPanel);

         InitializeComponent();
      }
   }
}


Nix kapisch, was musse nok makke?

bitte schnell mein leben retten, bin schon kurz vor dem sprung aus dem fenster...

thanx
ron

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo citizen.ron,

für den Fall, dass du noch nicht gesprungen bist, steht in vordrängelnde Controls (Control.Dock) eine Erklärung.

Für eine Lösung musst du wohl zwei interne Panels verwenden (also _headerPanel und z.B. _contentPanel) und es so managen, das this.Controls _contentPanel.Controls liefert, so dass von außen hinzugefügte Controls in dem Content-Panel landen.

herbivore

citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 18 Jahren

hi herbivore,

das mit dem ContentPanel war auch mein erster Gedanke.

da ich dann aber das ereignis ControlsAdded überwachen muss, sah mein code etwa so aus:

  
      protected override void OnControlAdded(ControlEventArgs e)
      {
         this._ContentPanel.Controls.Add(e.Control);   
         this.Controls.Remove(e.Control);       // wenn ich das nicht tue, bleibt das control zusätzlich im RollupPanel
      }


ausserdem führt diese implementierung zu einer fehlermeldung sinngemäß:
_
"child" ist kein element des blabla-containers_

wenn ich zur entwurfszeit ein control in das RollupPanel plaziere.

???

tia
ron

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo citizen.ron,

erstens brauchst du den Event m.E. nicht, da du Panels.Controls problemlos überschreiben kannst:

public virtual ControlCollection Controls { get; }

Und zweitens wäre

this.Controls.Remove(e.Control);

schlicht überflüssig, da ein Control immer nur in einer ControlsCollection enthalten sein kann. Sprich das Add führt ein automatisches Remove in der alten Collection aus. Add reicht also.

herbivore

citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 18 Jahren

hi herbivore,

jetzt hast du mich komplett verloren.
wenn ich die controlcollection Controls überschreibe, was wäre dann dessen implementierung?
das hier❔

 
      public virtual ControlCollection Controls 
      { 
         get { return _ContentPanel.Controls; } 
      }

wie würde ich denn dann dem RollupPanel selbst noch controls hinzufügen können, (z.b. _contentPanel und _headerPanel)?

also nochmal zurück zu der stelle wo es bei mir kracht:

die klasse hat im minimalmodus folgende implementierung:

 

{
   [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
   public partial class RollupPanel : Panel
   {
      [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
      public  Panel     HeaderPanel;
      private Panel     _ContentPanel;

      public RollupPanel()
      {
         Dock = DockStyle.Top;

      // Create a HeaderPanel
         HeaderPanel = new System.Windows.Forms.Panel();
         HeaderPanel.BackColor = System.Drawing.Color.DarkSeaGreen;
         HeaderPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
         HeaderPanel.Dock = System.Windows.Forms.DockStyle.Top;
         HeaderPanel.Name = "_HeaderPanel";
         HeaderPanel.Height = 23;
         HeaderPanel.TabIndex = 0;
         Controls.Add(this.HeaderPanel);

      // Create a ContentPanel
         _ContentPanel = new System.Windows.Forms.Panel();
         _ContentPanel.BackColor = System.Drawing.Color.White;
         _ContentPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
         _ContentPanel.Dock = System.Windows.Forms.DockStyle.Fill;
         _ContentPanel.Name = "_ContentPanel";
         _ContentPanel.TabIndex = 1;
         Controls.Add(this._ContentPanel);

         InitializeComponent();
      }

    }


Ohne das _contentPanel haben wir das Problem des Dockings, wie am Anfang des Threads beschrieben.

Mit _contentPanel ist das Problem, dass Elemente, die ich jetzt zur Entwurfszeit im RollupPanel plaziere, in den Hintergrund des _contentPanels treten! und nicht in ihm zu liegen kommen, also:

Fange ich, wie zuvor gezeigt, das Ereignis ControlAdded ab, mit nachstehender Implementierung:

 
protected override void OnControlAdded(ControlEventArgs e)
{
   if ((e.Control.Name != this.Name) && (e.Control.Name != "_HeaderPanel") && (e.Control.Name != "_ContentPanel"))
   {
      _ContentPanel.Controls.Add(e.Control);
   }
}

wirft mir die IDE beim Versuch ein Control im RollupPanel zu plazieren die Fehlermeldung

"child" ist kein untergeordnetes Steuerelement des übergeordneten Elements

aus.

und gleich noch ne frage:
wie kriege ich denn hin, dass zum beispiel zu entwurfszeit das headerpanel selektierbar ist (es zu veröffentlichen hat alleine nicht geholfen)?
bei einem splitterpanel bspw. sind doch zur entwurfszeit auch noch subelemente selektierbar.

und wie kann ich das ding eigentlich implementieren, ohne dass es überhaupt ein erbe von Panel ist? Die Schnittstelle IContainerControl scheint mir da nicht das richtige zu sein...

d.i.v.

ron

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo citizen.ron,

das hier?

im Prinzip ja, aber override statt virtual.

wie würde ich denn dann dem RollupPanel selbst noch controls hinzufügen können, (z.b. _contentPanel und _headerPanel)?

über base.Controls.Add

Ich denke die Folgefragen und auch das OnControlAdded erübrigt sich dann.

wie kriege ich denn hin, dass zum beispiel zu entwurfszeit das headerpanel selektierbar ist (es zu veröffentlichen hat alleine nicht geholfen)?

Sorry, mit Entwurfszeit kenne ich mich nicht aus. Ich benutze kein VS o.ä.

und wie kann ich das ding eigentlich implementieren, ohne dass es überhaupt ein erbe von Panel ist?

Warum soll es nicht von Panel erben? Ist doch gut.

herbivore

citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 18 Jahren

hey herbivore,

danke für deine hilfe, funzt jetzt.

nur für´s protokoll:

im Prinzip ja, aber override statt virtual.

liefert Fehlermeldung des Compilers:

RollupPanel.Controls.get": Der geerbte Member "System.Windows.Forms.Control.Controls.get" kann nicht überschrieben werden, weil er nicht als "virtual", "abstract" oder "override" markiert ist.

muss also virtual oder new bleiben.

thanx again

ron

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo citizen.ron,

dann hast du vermutlich noch 1.1. Unter 2.0 ist es virtual und deshalb wäre da override angezeigt.

herbivore

citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 18 Jahren

nope, ist 2.0,

hab aber rausgefunden, was uns auf den leim geschickt hat: in der online hilfe erscheint unter panel zunächst das panel aus dem namespace system.web.ui.webcontrols; dort ist das property tatsächlich als virtual deklariert.

der korrekte hilfetext ist bei mir unter

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.de/CPref17/html/P_System_Windows_Forms_Control_Controls.htm

zu finden und nennt Controls tatsächlich nur als

public ControlCollection Controls { get; }

gruß

ron

D
462 Beiträge seit 2005
vor 18 Jahren

Hallo!

Ich stehe gerade vor genau dem gleichen Problem. Gibt es dazu bereits eine Lösung?

Edit:
Hab mir gerade eine Lösung gebastelt, die einfach die Location der Childs korrigiert:

		void GroupPanel_ControlAdded(object sender, ControlEventArgs e)
		{
			CorrectChildLocation(e.Control);
			e.Control.LocationChanged += new EventHandler(Control_LocationChanged);
		}

		void Control_LocationChanged(object sender, EventArgs e)
		{
			CorrectChildLocation((Control)sender);
		}

		private void CorrectChildLocation(Control c)
		{
			if ((c.Location.Y <= header.Height)
				c.Location = new Point(c.Location.X, header.Height + 1);
		}

Wobei header das Control ist, das immer sichtbar ist und ich vor dem ControlAdded-Eventhandler eingefügt habe (mit Dock = DockStyle.Top).

Funkioniert einwandfrei!

mfg

D
462 Beiträge seit 2005
vor 18 Jahren

Die oben genannte Lösung ist nicht ganz sauber, da trotzdem noch das Dock-Problem besteht, habe es jedoch gerade behoben. Falls Interesse besteht, werde ich den benötigten Code posten, sobald ich mit dem Testen fertig bin!

citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 15 Jahren
Padding nicht berücksichtigt bei verschachteltem Container-Control

hi developerx,

hast du seinerzeit das docking-problem gelöst?

hi zusammen,

ich habe einen Panel-Erben, der in seinem Inneren eine GroupBox darstellt:


public class GroupPanel : Panel
{
#region Members
// Controls
   private GroupBox           groupBox;
#endregion

#region .ctor(s)
   public GroupPanel() : base()
   {
      SetStyle( ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true );
      Padding = new Padding(1);

   // groupBox
      groupBox = new GroupBox();
      groupBox.Padding = new Padding(3, 3, 3, 3);
      groupBox.Dock = DockStyle.Fill;
      groupBox.Name = "groupBox";
      groupBox.TabIndex = 0;
      groupBox.BackColor = Color.Transparent;
      base.Controls.Add(groupBox);
  }
#endregion
}


Eingebettete Steuerelemente sollen jetzt in der GroupBox "landen", was zur Überschreibung von Controls führt:


#region Overrides
   public virtual new ControlCollection Controls
   {
      get { return groupBox.Controls; }
   }
   protected override void OnControlAdded(ControlEventArgs e)
   {
      base.OnControlAdded(e);
      e.Control.BringToFront();
   }
#endregion

Mit der Padding-Eigenschaft des Panels wird nun logischerweise der Abstand der eingebetteten GroupBox vom Panel-Außenrand gesteuert.

Ich möchte aber den Abstand der nun in das Control platzierten Elemente zum GroupBox-Rand steuern können.
Hierfür habe ich eine Eigenschaft namens InnerPadding angelegt:


#region Properties
   public virtual Padding InnerPadding
   {
      get { return groupBox.Padding; }
      set { groupBox.Padding = value; }
   }
#endregion

**Das Problem **:
Lege ich nun bspw. eine Textbox in das Control und docke es bspw. Bottom, wird es in die GroupBox gedockt, berücksichtigt aber das Padding der GroupBox nicht.
Ausserdem bin ich in der Lage, mit dem Designer das innere Steuerelemente aus den Grenzen der GroupBox herauszuziehen, also in den Bereich zwischen Panel-Außenrand und Groupbox - das darf ja eigentlich auch nicht sein.

Ich vermute man könnte das über die Eigenschaft ClientRectangle des Panels steuern, aber die ist ja schreibgeschützt.

Danke für Eure Hilfe

ron

Sieht jemand hier, was ich falsch mache oder nicht berücksichtige?

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo citizen.ron,

Lege ich nun bspw. eine Textbox in das Control und docke es bspw. Bottom, wird es in die GroupBox gedockt, berücksichtigt aber das Padding der GroupBox nicht.

also wenn das Control tatsächlich in der GroupBox landet, dann sollte auch deren Padding berücksichtigt werden.

Ausserdem bin ich in der Lage, mit dem Designer das innere Steuerelemente aus den Grenzen der GroupBox herauszuziehen, also in den Bereich zwischen Panel-Außenrand und Groupbox - das darf ja eigentlich auch nicht sein.

Also das der Designer durcheinander kommt, wenn du so "Schweinereien" machst, wie die Controls-Property zu überschreiben, finde ich mehr oder weniger unausweichlich.

herbivore

citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 15 Jahren

hi herbivore,

Also das der Designer durcheinander kommt, wenn du so "Schweinereien" machst, wie die Controls-Property zu überschreiben, finde ich mehr oder weniger unausweichlich.

Diese "Schweinerei" hat mir ein von mir hochgeachteter Experte dieses Forums im gleichen Thread vor zwei Jahren vorgeschlagen:

...da du Panels.Controls problemlos überschreiben kannst

Aber vielleicht hast Du deine Meinung ja inzwischen geändert 😉

Wie auch immer: m.E.n. ist es durchaus üblich, das Controls-Property auf ein ChildControl umzuleiten - das sieht man immer mal wieder auf einschlägigen C# Seiten.

Oder kennst Du einen anderen/besseren Weg, das Hinzufügen eines Steuerelements in einen untergeordneten Container des eigentlichen Controls umzuleiten?

Gruß
Ron

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo citizen.ron,

Aber vielleicht hast Du deine Meinung ja inzwischen geändert 😉

nö, ich benutze nur den Designer nicht. 🙂

Unabhängig vom Designer hat der Vorschlag leider nur den Makel, dass Controls nicht virtual ist. 🙂

herbivore

Gelöschter Account
vor 15 Jahren
public class mycontrol : Control
    {
        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);

            otherControlCollection.Add(e.Control);
        }
    }

wenn man ein control einer anderen controlcolection zuweist, dann wird es vorher automatisch bei der alten collection ausgetragen.

citizen.ron Themenstarter:in
432 Beiträge seit 2005
vor 15 Jahren

nope,
das führt zu der Fehlermeldung

"child" ist kein untergeordnetes Steuerelement dieses übergeordneten Elements.

wenn man im designer ein steuerelement in das panel platziert.

Gelöschter Account
vor 15 Jahren

^^. ich muss zugeben, da sich den designer auch nciht wirklich verwende. höchstens um schnell ein minitool zu bauen und dafür eine schnelle statische oberfläche zu bauen.