Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Container control: Docking chaos der child controls!
citizen.ron
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

Container control: Docking chaos der child controls!

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
citizen.ron
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
citizen.ron
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

beantworten | zitieren | melden

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
Zitat
"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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo citizen.ron,
Zitat
das hier?
im Prinzip ja, aber override statt virtual.
Zitat
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.
Zitat
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.ä.
Zitat
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
private Nachricht | Beiträge des Benutzers
citizen.ron
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

beantworten | zitieren | melden

hey herbivore,

danke für deine hilfe, funzt jetzt.

nur für´s protokoll:
Zitat
im Prinzip ja, aber override statt virtual.

liefert Fehlermeldung des Compilers:
Zitat
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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo citizen.ron,

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

herbivore
private Nachricht | Beiträge des Benutzers
citizen.ron
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
DeveloperX
myCSharp.de - Member



Dabei seit:
Beiträge: 462
Herkunft: .at/ooe&stmk

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
DeveloperX
myCSharp.de - Member



Dabei seit:
Beiträge: 462
Herkunft: .at/ooe&stmk

beantworten | zitieren | melden

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!
private Nachricht | Beiträge des Benutzers
citizen.ron
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

Padding nicht berücksichtigt bei verschachteltem Container-Control

beantworten | zitieren | melden

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?
Attachments
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo citizen.ron,
Zitat
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.
Zitat
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
private Nachricht | Beiträge des Benutzers
citizen.ron
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

beantworten | zitieren | melden

hi herbivore,
Zitat
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:
Zitat
...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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo citizen.ron,
Zitat
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
private Nachricht | Beiträge des Benutzers
Gelöschter Benutzer

beantworten | zitieren | melden

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
myCSharp.de - Member

Avatar #avatar-1693.jpg


Dabei seit:
Beiträge: 432
Herkunft: Frankfurt / Main

Themenstarter:

beantworten | zitieren | melden

nope,
das führt zu der Fehlermeldung
Zitat
"child" ist kein untergeordnetes Steuerelement dieses übergeordneten Elements.

wenn man im designer ein steuerelement in das panel platziert.
private Nachricht | Beiträge des Benutzers
Gelöschter Benutzer

beantworten | zitieren | melden

^^. 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.