Display a MultilineStringEditor at design-time to edit the lines of an edit-control?

末鹿安然 提交于 2019-12-05 23:19:22
Reza Aghaei

The editor which you are looking for is StringArrayEditor which is used to edit string[] properties. It also is internal to System.Design.

To show StringArrayEditor at design-time using a designer verb you need to:

  1. Define a string[] Lines property in your control which gets or sets different lines of texts in Text property. In fact we will edit this property which cause the Text property getting edited.
  2. To be able to show the default editor for Lines property, create a class implementing ITypeDescriptorContext, IServiceProvider and IWindowsFormsEditorService interfaces. This way, after getting the editor of Lines property, you can call its EditValue method which shows the desired editor.
  3. Create a custom ActionList containing a method to show the editor. In this method, you should use the class which you created in previous step to show the editor for the property and after editing the property, set the edited value for property.
  4. Create a custom designer for your control and override its ActionLists to return your custom action list.
  5. Decorate the control with Designer attribute, registering your custom designer for the control.

Example

To make the example working, it's enough to copy and paste following code to a file in your Windows Forms application. Don't forget to add reference to System.Design assembly. After you build the project, you can drop an instance of MyControl on a form and using the smart tag window, you can click on Edit Text Lines... link to show StringArrayEditor dialog to edit the Line (and consequently Text) property. Here is the code:

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;

[Designer(typeof(MyControlDesigner))]
public class MyControl : Control
{
    public string[] Lines
    {
        get
        {
            return this.Text.Split(new string[] { Environment.NewLine },
                StringSplitOptions.None);
        }
        set
        {
            if (value != null)
                this.Text = string.Join(Environment.NewLine, value);
        }
    }
}
public class MyControlDesigner : ControlDesigner
{
    public override DesignerActionListCollection ActionLists
    {
        get
        {
            var list = new DesignerActionListCollection();
            list.Add(new MyControlActionList(this));
            return list;
        }
    }

}
public class MyControlActionList : DesignerActionList
{
    MyControlDesigner designer;
    MyControl Control { get { return (MyControl)designer.Control; } }
    public MyControlActionList(MyControlDesigner designer) : base(designer.Component)
    {
        this.designer = designer;
    }
    public override DesignerActionItemCollection GetSortedActionItems()
    {
        DesignerActionItemCollection items = new DesignerActionItemCollection();
        items.Add(new DesignerActionMethodItem(this, "EditTextLines",
           "Edit Text Lines...", "Behavior", "Opens the Lines collection editor", false));
        return items;
    }
    public void EditTextLines()
    {
        var linesPropertyDescriptor = TypeDescriptor.GetProperties(this.Control)["Lines"];
        var context = new TypeDescriptionContext(this.Control, linesPropertyDescriptor);
        var editor =(UITypeEditor)linesPropertyDescriptor.GetEditor(typeof(UITypeEditor));
        var lines = (this.Control).Lines;
        var result = (string[])editor.EditValue(context, context, lines);
        if (!result.SequenceEqual(lines))
            linesPropertyDescriptor.SetValue(this.Control, result);
    }
}
public class TypeDescriptionContext : ITypeDescriptorContext, IServiceProvider,
    IWindowsFormsEditorService
{
    private Control component;
    private PropertyDescriptor editingProperty;
    public TypeDescriptionContext(Control component, PropertyDescriptor property)
    {
        this.component = component;
        editingProperty = property;
    }
    public IContainer Container { get { return component.Container; } }
    public object Instance { get { return component; } }
    public void OnComponentChanged()
    {
        var svc = (IComponentChangeService)this.GetService(
            typeof(IComponentChangeService));
        svc.OnComponentChanged(component, editingProperty, null, null);
    }
    public bool OnComponentChanging() { return true; }
    public PropertyDescriptor PropertyDescriptor { get { return editingProperty; } }
    public object GetService(Type serviceType)
    {
        if ((serviceType == typeof(ITypeDescriptorContext)) ||
            (serviceType == typeof(IWindowsFormsEditorService)))
            return this;
        return component.Site.GetService(serviceType);
    }
    public void CloseDropDown() { }
    public void DropDownControl(Control control) { }
    DialogResult IWindowsFormsEditorService.ShowDialog(Form dialog)
    {
        IUIService service = (IUIService)(this.GetService(typeof(IUIService)));
        return service.ShowDialog(dialog);
    }
}

Note

You can find a more robust implementation of ITypeDescriptorContext, IServiceProvider and IWindowsFormsEditorService interfaces which I posed in response to this question:

Then in your custom ActionList class, you can show Lines property editor this way:

EditorServiceContext.EditValue(this.designer, base.Component, "Lines");

That's exactly the same way which is used in RichTextBoxDesigner.

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