2010-04-22 9 views
16

Ich entwerfe eine einfache Expandersteuerung.Benutzersteuerung als Container zur Entwurfszeit

Ich habe von UserControl abgeleitet, innere Steuerelemente gezeichnet, gebaut, ausgeführt; alles ok.

Da ein inneres Steuerelement ein Panel ist, möchte ich es als Container zur Entwurfszeit verwenden. Tatsächlich habe ich die Attribute verwendet:

[Designer(typeof(ExpanderControlDesigner))] 
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] 

Großartig, sage ich. Aber es ist nicht ...

Das Ergebnis ist, dass ich es als Behälter zur Entwurfszeit verwenden kann, aber:

  • Die zusätzlichen Kontrollen die inneren Kontrollen zurückgehen bereits eingebettet in der Benutzersteuerung
  • selbst wenn wir eine Kontrolle hinzugefügt zur Design-Zeit nach oben drücken, während der Laufzeit ist es wieder zurück auf Kontrollen eingebettet in die Benutzersteuerung
  • ich kann den Containerbereich zur Entwurfszeit in einen Panel-Bereich beschränken

Was fehlt mir? Hier ist der Code für die Vollständigkeit ... warum funktioniert dieser Codeschnipsel nicht?

[Designer(typeof(ExpanderControlDesigner))] 
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] 
public partial class ExpanderControl : UserControl 
{ 
    public ExpanderControl() 
    { 
     InitializeComponent(); 
.... 

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] 
internal class ExpanderControlDesigner : ControlDesigner 
{ 
    private ExpanderControl MyControl; 

    public override void Initialize(IComponent component) 
    { 
     base.Initialize(component); 

     MyControl = (ExpanderControl)component; 

     // Hook up events 
     ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService)); 
     IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService)); 

     s.SelectionChanged += new EventHandler(OnSelectionChanged); 
     c.ComponentRemoving += new ComponentEventHandler(OnComponentRemoving); 
    } 

    private void OnSelectionChanged(object sender, System.EventArgs e) 
    { 

    } 

    private void OnComponentRemoving(object sender, ComponentEventArgs e) 
    { 

    } 

    protected override void Dispose(bool disposing) 
    { 
     ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService)); 
     IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService)); 

     // Unhook events 
     s.SelectionChanged -= new EventHandler(OnSelectionChanged); 
     c.ComponentRemoving -= new ComponentEventHandler(OnComponentRemoving); 

     base.Dispose(disposing); 
    } 

    public override System.ComponentModel.Design.DesignerVerbCollection Verbs 
    { 
     get 
     { 
      DesignerVerbCollection v = new DesignerVerbCollection(); 

      v.Add(new DesignerVerb("&asd", new EventHandler(null))); 

      return v; 
     } 
    } 
} 

ich gefunden habe viele Ressourcen (Interaction, designed, limited area), aber nichts war sehr nützlich für die operative sein ...

Eigentlich gibt einen Trick, da System.Windows.Forms Klassen wie üblich gestaltet sein und zur Laufzeit ein korrektes Verhalten haben (zB TabControl).

Antwort

16

ParentControlDesigner weiß nicht, was Sie tun möchten. Es weiß nur, dass Sie möchten, dass Ihr Benutzersteuerelement ein Container ist.

Was Sie tun müssen, ist Ihre eigene Designer zu implementieren, die Design-Modus auf dem Panel ermöglicht:

using System.ComponentModel; 
    using System.Windows.Forms; 
    using System.Windows.Forms.Design; 

    namespace MyCtrlLib 
    { 
     // specify my custom designer 
     [Designer(typeof(MyCtrlLib.UserControlDesigner))] 
     public partial class UserControl1 : UserControl 
     { 
      public UserControl1() 
      { 
       InitializeComponent(); 
      } 

      // define a property called "DropZone" 
      [Category("Appearance")] 
      [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
      public Panel DropZone 
      { 
       get { return panel1; } 
      } 
     } 

     // my designer 
     public class UserControlDesigner : ParentControlDesigner 
     { 
      public override void Initialize(System.ComponentModel.IComponent component) 
      { 
       base.Initialize(component); 

       if (this.Control is UserControl1) 
       { 
        this.EnableDesignMode(
         (UserControl1)this.Control).DropZone, "DropZone"); 
       } 
      } 
     } 
    } 

Das erfuhr ich von Henry Minute auf Codeproject. Siehe den Link für einige Verbesserungen an der Technik.

+0

Es funktioniert ! Aber tatsächlich hat es nicht die folgenden Defekte: Sie können den "WorkingArea" verschieben/vergrößern (welche Unterschiede hat die "DropZone"?) aber zur Laufzeit wird es nicht reflektiert; Die doppelten Steuerelemente zur Entwurfszeit können nicht auf Containergrenzen ausgerichtet werden. – Luca

+0

Ich habe die gleichen 2 Probleme und wundere mich, wie das behoben werden kann – Telanor

+0

Aus der Spitze meines Kopfes Ich bin mir nicht sicher, wie Sie mit diesen Problemen umgehen. Hast du den Link angeschaut? Er könnte diese mit seiner verbesserten Version gelöst haben. http://www.codeproject.com/KB/misctrl/NestedControlDesigner.aspx –

2

Zusätzlich zu der Antwort oben. In den Kommentaren wird erwähnt, dass der Benutzer den WorkingArea ziehen kann. Mein Problem besteht darin, das WorkingArea-Panel in ein anderes Panel einzufügen und es auf Dock.Fill zu setzen. Um den Benutzer nicht zulassen, um es zu ändern zurück, ich habe eine Klasse Content erstellt, die überschreibt und versteckt die Dock-Eigenschaft:

class ContentPanel : Panel 
{ 
    [Browsable(false)] 
    public override DockStyle Dock 
    { 
     get { return base.Dock; } 
     set { base.Dock = DockStyle.Fill; } 
    } 
} 

Für mich ist es dadurch ausreichend sicher. Wir verwenden das Steuerelement nur intern, also möchten wir hauptsächlich verhindern, dass Entwickler versehentlich Dinge herumschleppen. Es gibt sicherlich Möglichkeiten, es zu vermasseln.

3

Um den Arbeitsbereich an einer Bewegung/Größe verändert im Designer verhindern Sie eine Klasse für diesen Arbeitsbereich erstellen, die den Ort versteckt, Höhe, Breite, Größe Eigenschaften vom Designer:

public class WorkingArea : Panel 
{ 
    [Browsable(false)] 
    [EditorBrowsable(EditorBrowsableState.Never)] 
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
    public new Point Location 
    { 
     get 
     { 
      return base.Location; 
     } 
     set 
     { 
      base.Location = value; 
     } 
    } 
... 
} 
Verwandte Themen