First part:
1. Start new class library for .NET Framework (not core)
2. Name it MyControls.
3. Rename Class1 to MyButton.
4. Reference System.Windows.Forms in my case it was like: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Windows.Forms.dll
5. MyButton inherit from Button.
6. Add property like:
public string MyProperty { get; set; }
7. Create new App Windows forms for .NET Framework (not core)
8. Add new tab in toolbox
9. Drag and drop MyControls.dll --- Second part - smart tag: 10. Add attribute [Designer(typeof(MyButtonDesigner))]:
using System.ComponentModel; using System.Windows.Forms; namespace MyControls { [Designer(typeof(MyButtonDesigner))] public class MyButton: Button { public string MyProperty { get; set; } } }11. Add class MyButtonDesigner
12. Add reference to System.Design C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Design.dll in usings add System.Windows.Forms.
13. Add class MyButtonDesigner and inherit from ControlDesigner:
using System.ComponentModel.Design; using System.Windows.Forms.Design; namespace MyControls { public class MyButtonDesigner: ControlDesigner { private DesignerActionListCollection _myButtonActionLists; public override DesignerActionListCollection ActionLists { get { if (_myButtonActionLists is null) { _myButtonActionLists = new DesignerActionListCollection { new MyButtonActionList(Component) }; } return _myButtonActionLists; } } } }14. Add class MyButtonActionList, inherit from DesignerActionList:
using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Reflection; namespace MyControls { public class MyButtonActionList: DesignerActionList { private readonly MyButton _myButton; private readonly DesignerActionUIService _designerActionUiSvc = null; public MyButtonActionList(IComponent component) : base(component) { _myButton = component as MyButton; _designerActionUiSvc = GetService(typeof(DesignerActionUIService)) as DesignerActionUIService; } public string MyProperty { get => _myButton.MyProperty; set { GetPropertyByName("MyProperty").SetValue(_myButton, value); _designerActionUiSvc.Refresh(Component); } } public override DesignerActionItemCollection GetSortedActionItems() { DesignerActionItemCollection items = new DesignerActionItemCollection(); items.Add(new DesignerActionHeaderItem("My Smart tag")); items.Add(new DesignerActionPropertyItem("MyProperty", "MyProperty")); return items; } private PropertyDescriptor GetPropertyByName(string propName) { var prop = TypeDescriptor.GetProperties(_myButton)[propName]; if (null == prop) throw new ArgumentException( "Matching MyProperty property not found!", propName); return prop; } } }Example until now download from here. --- Third part - UIEditor: 15. In MyButton change MyProperty to:
public MyPropertyType MyProperty { get; set; }16. Add new class MyPropertyType, decorate with Editor and TypeConverter:
using System.ComponentModel; using System.Drawing.Design; namespace MyControls { [Editor(typeof(MyButtonEditor), typeof(UITypeEditor))] [TypeConverter(typeof(MyPropertyTypeConverter))] public class MyPropertyType { public string AnotherMyProperty { get; set; } public MyPropertyType(string test) { AnotherMyProperty = test; } } }17. Add one more class MyPropertyTypeConverter:
using System; using System.ComponentModel; using System.Globalization; namespace MyControls { public class MyPropertyTypeConverter : TypeConverter { public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return true; } public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return true; } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is null) { return string.Empty; } return new MyPropertyType(value.ToString()); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { return ((MyPropertyType)value)?.AnotherMyProperty; } } }18. Again add class MyButtonEditor:
using System; using System.ComponentModel; using System.Drawing.Design; using System.Windows.Forms; using System.Windows.Forms.Design; namespace MyControls { public class MyButtonEditor: UITypeEditor { public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) => UITypeEditorEditStyle.Modal; public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { IWindowsFormsEditorService svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService; Form myForm = new Form(); svc?.ShowDialog(myForm); return new MyPropertyType("test"); } } }Example download from here.