WinForms Designer and TableLayoutPanel SmartTag Customization

痞子三分冷 提交于 2019-12-22 13:08:20

问题


I am trying to customize the existing Smart Tag content for a TableLayoutPanel Windows Forms control for use in the Windows Forms designer (I implemented a designer that leverages the WinForms designer features exposed by the System.ComponentModel.Design and System.Windows.Forms.Design namespaces). Whatever approach is offered as a solution, it's got to also work when my control is added to the Visual Studio toolbox and when my control is placed on a WinForm surface in design mode while in the Visual Studio IDE.

Here's what I'm trying to do: In design mode, a TableLayoutPanel control instance on a form displays an adornment that, when clicked, presents the Smart Tag panel composed of "actions", such as Add Column, Add Row, etc. (Some of these actions also appear as verbs under the property grid--I know how to modify those verbs: My question has to do with only the smart tag action list.)

What I want to do is amend the TableLayoutPanel control's design-time smart tag action list with some of my own items.

Unfortunately, it seems that to do this, you must associate the control with a custom designer. However, I don't want to use a custom designer or one that's derived from ControlDesigner. I found that when I do this, I lose all of the designer functionality the TableLayoutPanel control offers--such as seeing new rows, columns and being able to drag-and-drop controls onto its client surface. I must retain such visual design-time features of the TableLayoutPanel.

If I use the Designer attribute to specify the TableLayoutPanelDesigner class as the designer, then I'm out of luck because that class is marked as internal (https://referencesource.microsoft.com/#System.Design/System/Windows/Forms/Design/TableLayoutPanelDesigner.cs).

How can I leverage the existing designer for the WinForm TableLayoutPanel control yet also customize its smart tag's action list? Surely this must be accessible using reflection (but I couldn't figure out how).


回答1:


TableLayoutPanelDesiner is internal and has dependencies to other internal classes and you can not inherit from it. Also, it's not a good idea to create an new control designer for TableLayoutPanel from scratch because you will lose all of current designer functionalities.

A really good trick is finding the designer and manipulate designer at design-time. Look at the Do something! and the Back Color new items:

To do so, you can find the designer of your TableLayoutPanel at design-time and manipulate it. A good point is in OnHandleCreated method. You can get an instance of IDesignerHost from Site of the control and then get the designer.

Then you can get the current action list for the control and create a new action list containing all those action items and add some new action items to the list.

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


来源:https://stackoverflow.com/questions/52215265/winforms-designer-and-tablelayoutpanel-smarttag-customization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!