WinForms Designer和TableLayoutPanel SmartTag自定义

时间:2018-09-07 04:23:05

标签: c# .net winforms windows-forms-designer tablelayoutpanel

我正在尝试自定义TableLayoutPanel Windows窗体控件的现有智能标记内容,以供Windows窗体设计器中使用(我实现了一个设计器,该设计器利用了System.ComponentModel.Design和System.Windows公开的WinForms设计器功能。 Forms.Design名称空间)。无论采用哪种方法作为解决方案,当将控件添加到Visual Studio工具箱中以及将控件放置在Visual Studio IDE中的设计模式下的WinForm曲面上时,它也必须起作用。

这就是我想要做的: 在设计模式下,表单上的TableLayoutPanel控件实例显示装饰物,当单击该装饰物时,将显示由“动作”组成的“智能标记”面板,例如“添加列”,“添加行”等。属性网格-我知道如何修改这些动词:我的问题只与智能标记操作列表有关。)

我想要做的是用我自己的一些项修改TableLayoutPanel控件的设计时智能标记操作列表。

不幸的是,似乎要执行此操作,您必须将控件与自定义设计器关联。但是,我不想使用自定义设计器或从ControlDesigner派生的设计器。我发现执行此操作时,我失去了TableLayoutPanel控件提供的所有设计器功能-例如查看新行,新列以及将控件拖放到其客户端表面上。我必须保留TableLayoutPanel的这种可视化设计时功能。

如果我使用Designer属性将TableLayoutPanelDesigner类指定为设计器,则我不走运,因为该类被标记为内部(https://referencesource.microsoft.com/#System.Design/System/Windows/Forms/Design/TableLayoutPanelDesigner.cs)。

如何在WinForm TableLayoutPanel控件中利用现有设计器,又如何自定义其智能标记的动作列表?当然,必须可以使用反射来访问它(但是我不知道怎么做)。

1 个答案:

答案 0 :(得分:3)

TableLayoutPanelDesiner是内部的,具有对其他内部类的依赖,因此您不能从中继承。另外,从头开始为TableLayoutPanel创建新的控件设计器也不是一个好主意,因为您将失去所有当前的设计器功能。

一个非常好的技巧是在设计时找到设计师并操纵设计师。查看做点什么!背景色新项目:

enter image description here

为此,您可以在设计时找到TableLayoutPanel的设计者并对其进行操作。 OnHandleCreated方法是一个优点。您可以从控件的IDesignerHost获取Site的实例,然后获取设计器。

然后,您可以获得控件的当前操作列表,并创建一个包含所有这些操作项的新操作列表,并将一些新操作项添加到列表中。

MyTableLayoutPanel

using System;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
public class MyTableLayoutPanel : TableLayoutPanel
{
    private IDesignerHost designerHost;
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        if (DesignMode && Site != null)
        {
            designerHost = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (designerHost != null)
            {
                var designer = (ControlDesigner)designerHost.GetDesigner(this);
                if (designer != null)
                {
                    var actions = designer.ActionLists[0];
                    designer.ActionLists.Clear();
                    designer.ActionLists.Add(
                        new MyTableLayoutPanelActionList(designer, actions));
                }
            }
        }
    }
}

MyTableLayoutPanelActionList

using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows;
using System.Windows.Forms.Design;
public class MyTableLayoutPanelActionList : DesignerActionList
{
    MyTableLayoutPanel control;
    ControlDesigner designer;
    DesignerActionList actionList;
    public MyTableLayoutPanelActionList(ControlDesigner designer, 
        DesignerActionList actionList) : base(designer.Component)
    {
        this.designer = designer;
        this.actionList = actionList;
        control = (MyTableLayoutPanel)designer.Control;
    }
    public Color BackColor
    {
        get { return control.BackColor; }
        set
        {
            TypeDescriptor.GetProperties(Component)["BackColor"]
                .SetValue(Component, value);
        }
    }
    private void DoSomething()
    {
        MessageBox.Show("My Custom Verb added!");
    }
    public override DesignerActionItemCollection GetSortedActionItems()
    {
        var items = new DesignerActionItemCollection();
        foreach (DesignerActionItem item in actionList.GetSortedActionItems())
            items.Add(item);
        var category = "New Actions";
        items.Add(new DesignerActionMethodItem(this, "DoSomething", 
            "Do something!", category, true));
        items.Add(new DesignerActionPropertyItem("BackColor", "Back Color",
            category));
        return items;
    }
}