将控件添加到设计器中用户控件的面板

Adding controls to a panel on a User Control in designer

我有一个特定的要求,即创建一个具有特定常用功能的用户控件。对于该控件,我还要求允许其他开发人员在设计器模式下添加控件以制作特定的 UI。为此,我创建了一个用户控件,添加(示例)标签和按钮。我还添加了一个面板,允许在控件的特定区域添加附加控件。

然后我通过添加 [Designer] 标记和 [ControlDesigner] 使 class 在设计器模式下可见。这给出了添加具有一些固定内容的用户控件并向页面添加更多控件的预期效果。问题是用户可以在设计模式下移动面板,VisualStudio 会感到困惑,创建循环引用。我一定是遗漏了什么?我可以关闭面板的 resizing/positioning,即使我需要启用设计模式吗?

注意:我也尝试在设计模式下只使用用户控件,但添加的控件总是消失在用户控件上的固定控件后面。

代码和示例如下。欢迎任何suggestion/fixes..

以上是用户控件面板的视觉效果

上面是一个包含用户控件的表单,并向面板添加了一个自定义按钮。请注意面板拖动已启用,如果触摸,则会在 form.designer.cs 文件中创建一个循环引用,并且项目变得不稳定。

下面最后是用户控件class

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

using System.Windows.Forms.Design;

namespace wfcLib
{

    [DesignerAttribute(typeof(MyControlDesigner))]
    [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
    public partial class ucInput : UserControl
    {

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public Panel InternalPanel
        {
            get { return pnlContent; }
            set { pnlContent = value; }
        }
        public ucInput()
        {
            InitializeComponent();

        }

    }
    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public class MyControlDesigner : System.Windows.Forms.Design.ControlDesigner
    {
        public override void Initialize(IComponent c)
        {
            base.Initialize(c);
            ucInput ctl = (ucInput)c;
            EnableDesignMode(ctl.InternalPanel, "InternalPanel");
        }
    }
}

除了我关于使用派生的 Panel 及其自己的设计器覆盖 SelectionRules 属性 的评论外,另一种方法是利用设计器的 ISelectionService 以检测所选组件的变化并删除面板(如果已选中)。

这是通过覆盖控件的 Site 属性 来设置挂钩来实现的。另请注意,我将 InternalPanel 属性 更改为只读,因为您真的不希望它可写。

[DesignerAttribute(typeof(MyControlDesigner))]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public partial class ucInput : UserControl
{

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public Panel InternalPanel
    {
        get { return pnlContent; }
    }

    public ucInput()
    {
        InitializeComponent();
    }

    private ISelectionService selectionService;
    private IDesignerHost host;
    public override ISite Site
    {
        get
        {
            return base.Site;
        }
        set
        {
            host = null;
            UnSubscribeFromSelectionService();
            base.Site = value;
            if (value != null)
            {
                host = (IDesignerHost)this.Site.GetService(typeof(IDesignerHost));
                if (host != null)
                {
                    if (host.Loading)
                    {
                        // defer subscription to selection service until fully loaded
                        host.Activated += Host_Activated;
                    }
                    else
                    {
                        SubscribeToSelectionService();
                    }
                }
            }
        }
    }

    private void Host_Activated(object sender, EventArgs e)
    {
        host.Activated -= Host_Activated;
        SubscribeToSelectionService();
    }

    private void SubscribeToSelectionService()
    {
        selectionService = (ISelectionService)this.Site.GetService(typeof(ISelectionService));
        if (selectionService != null)
        {
            selectionService.SelectionChanging += OnSelectionChanging;
        }
    }

    private void UnSubscribeFromSelectionService()
    {
        if (selectionService != null)
        {
            selectionService.SelectionChanging -= OnSelectionChanging;
        }
    }

    private void OnSelectionChanging(object sender, EventArgs e)
    {
        if (selectionService.GetComponentSelected(pnlContent))
        {
            selectionService.SelectionChanging -= OnSelectionChanging;
            selectionService.SetSelectedComponents(new[] { pnlContent }, SelectionTypes.Remove);
            selectionService.SelectionChanging += OnSelectionChanging;
        }
    }
}

编辑: 原始代码忽略了 SelectionService 在加载 IDesignerHost 时不可用的问题。添加了延迟订阅的代码,直到 IDesignerHost 被激活。