用户控件在设计时作为容器

我正在设计一个简单的扩展器控件。

我派生自UserControl,绘制内部控件,构建,运行; 一切都好。

由于内部控件是Panel,我想在设计时将其用作容器。 的确,我使用了以下属性:

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

太棒了,我说。 但它不是……

结果是我可以在设计时将它用作容器,但是:

  • 添加的控件返回已嵌入用户控件中的内部控件
  • 即使我在设计时将顶部控件添加到顶部,在运行时也会再次返回嵌入到用户控件的控件
  • 我无法在设计时将容器区域限制为Panel区域

我错过了什么? 这是完整性的代码…为什么这段代码不起作用?

 [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; } } } 

我找到了很多资源( 互动 , 设计 , 有限的区域 ),但没有什么是有用的…

实际上有一个技巧,因为System.Windows.Forms类可以设计(像往常一样)并在运行时具有正确的行为(例如TabControl)。

ParentControlDesigner不知道你想做什么。 它只知道您希望UserControl成为容器。

您需要做的是实现您自己的设计器,该设计器在面板上启用设计模式:

  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"); } } } } 

我从CodeProject的Henry Minute那里学到了这一点。 有关该技术的一些改进,请参阅该链接。

除了上面的答案。 在评论中提到,用户可以拖动WorkingArea。 我的解决方法是将WorkingArea面板包含在另一个面板中,将其设置为Dock.Fill。 为了禁止用户更改它,我创建了一个覆盖和隐藏Dock属性的类ContentPanel:

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

对我来说,这使它足够安全。 我们只在内部使用控件,因此我们主要希望防止开发人员意外拖延。 无论如何,肯定有办法搞砸了。

要防止在设计器中移动/调整工作区域,您必须为该工作区创建一个隐藏设计器的“位置”,“高度”,“宽度”,“大小”属性的类:

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