WinForms Designer and TableLayoutPanel SmartTag Customization
Asked Answered
E

1

2

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).

Emulsoid answered 7/9, 2018 at 4:23 Comment(2)
Yup, not even being able to see the source code for the designer from the Reference Source is yet another hint. They did not trust programmers to get it right and don't want to support it. All that you can do is use a decent decompiler (like Reflector, ILSpy) and re-generate the source code from System.Design.dll And worry a bit about getting it right, albeit that extending or replacing the action list isn't all that risky.Know
Woe is me... :( Thanks for the sanity check. I'm satisfied with your comment as the answer--post as such and I'll accept.Emulsoid
T
4

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:

enter image description here

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;
    }
}
Tichonn answered 18/1, 2019 at 3:55 Comment(3)
FANTASTIC--So very much appreciated! Full of great general as well as specific information that I can leverage in all sorts of ways. Many thanks!Emulsoid
Oh, I normally wouldn't do this, but if you're up for another question challenge and you might have some insight, please see my unanswered question also about designers and Winforms: #54224024Emulsoid
In fact I came from there ;) I'll share my idea if I have any useful idea.Tichonn

© 2022 - 2024 — McMap. All rights reserved.