如何使复合组件可用于设计器?

R. *_*des 14 c# components designer visual-studio winforms

我正在尝试编写自定义WinForms组件,我编写了几个简单的验证器组件,用于ErrorProvider自动挂钩验证事件的子类.所有这些组件都可以添加到表单中,并且仅使用设计器进行连接,这要归功于IExtenderProvider.

现在尝试上升一个级别,我试图让一个复合验证器可以与设计师一起使用.我可以解决它并使用代码,但这非常简单.我想让它以设计师的方式工作.

我的困难在于暴露一个属性,该属性是同一形式的其他验证器的集合.验证器都直接从Component继承,并实现一个IControlValidator接口.我愿意改变它,让它们从ValidatorComponent基类继承,如果有帮助的话.

我想到了几个解决方案,但要么我不喜欢它们,要么我不能让它们工作:

  1. 使验证器成为不可见的控件,并且复合验证器包含它们,类似于它的Panel作用;

    这个我不喜欢,因为它更像是一个黑客,不得不把它们放在真正的控制之中,只是感觉不对;

  2. 使用工具栏时使用集合编辑器;

    我环顾网络,发现了几篇关于此的文章,但我无法让它发挥作用.至少没有建立我自己的编辑表格,这对于实验项目来说太麻烦了.

    我承认我没有花太多时间尝试这个,因为我意识到使用标准CollectionEditor会把我锁定到使用一组固定的验证器类型(它会,不是吗?).

    我还想过创建一个ValidatorReference具有单一属性类型的简单类,IControlValidator并将其用作简单集合编辑器的元素类型.然后我会添加其中一个,并在其属性网格中将属性设置为现有的验证器组件.这个似乎很容易上班,但失去吸引力,因为它是如此明显的黑客.

任何人有任何其他想法?有什么我想念的东西,这其实很简单吗?

Mig*_*elo 7

为什么不创建一个编辑器来做这个??? 你认为这听起来有点矫枉过正,但事实并非如此.

我将展示一个样本.

样品说明

在这个示例中,我将创建一个名为的ButtonActivityControl控件,它可以使用一个名为ButtonsButton的类型的数组(即Button[])来对同一表单中的其他控件进行多次引用.

该属性标有自定义编辑器,可以轻松引用页面中的控件.编辑器显示一个由选中列表框组成的表单,该表用于选择多个控件,这些控件采用完全相同的形式.

创建示例的步骤

1)一个名为ReferencesCollectionEditorForm的表单

  • 在其中放置一个CheckedListBox,
  • 放置一个"确定"按钮
  • 将以下代码放在表单类中

ReferencesCollectionEditorForm代码:

public partial class ReferencesCollectionEditorForm : Form
{
    public ReferencesCollectionEditorForm(Control[] available, Control[] selected)
    {
        this.InitializeComponent();
        List<Control> sel = new List<Control>(selected);
        this.available = available;
        if (available != null)
            foreach (var eachControl in available)
                this.checkedListBox1.Items.Add(new Item(eachControl),
                    selected != null && sel.Contains(eachControl));
    }

    class Item
    {
        public Item(Control ctl) { this.control = ctl; }
        public Control control;
        public override string ToString()
        {
            return this.control.GetType().Name + ": " + this.control.Name;
        }
    }

    Control[] available;

    public Control[] Selected
    {
        get
        {
            List<Control> selected = new List<Control>(this.available.Length);
            foreach (Item eachItem in this.checkedListBox1.CheckedItems)
                selected.Add(eachItem.control);
            return selected.ToArray();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

2)一个UITypeEditor

ReferencesCollectionEditor:

public class ReferencesCollectionEditor : UITypeEditor
{
    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        List<Control> available = new List<Control>();

        ButtonActivityControl control = context.Instance as ButtonActivityControl;
        IDesignerHost host = provider.GetService(typeof(IDesignerHost)) as IDesignerHost;
        IComponent componentHost = host.RootComponent;
        if (componentHost is ContainerControl)
        {
            Queue<ContainerControl> containers = new Queue<ContainerControl>();
            containers.Enqueue(componentHost as ContainerControl);
            while (containers.Count > 0)
            {
                ContainerControl container = containers.Dequeue();
                foreach (Control item in container.Controls)
                {
                    if (item != null && context.PropertyDescriptor.PropertyType.GetElementType().IsAssignableFrom(item.GetType()))
                        available.Add(item);
                    if (item is ContainerControl)
                        containers.Enqueue(item as ContainerControl);
                }
            }
        }

        // collecting buttons in form
        Control[] selected = (Control[])value;

        // show editor form
        ReferencesCollectionEditorForm form = new ReferencesCollectionEditorForm(available.ToArray(), selected);

        form.ShowDialog();

        // save new value
        Array result = Array.CreateInstance(context.PropertyDescriptor.PropertyType.GetElementType(), form.Selected.Length);
        for (int it = 0; it < result.Length; it++)
            result.SetValue(form.Selected[it], it);
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

3)使用相同形式的其他控件的控件

自定义控制代码:

public class ButtonActivityControl : Control, ISupportInitialize
{
    [Editor(typeof(ReferencesCollectionEditor), typeof(UITypeEditor))]
    public Button[] Buttons { get; set; }

    Dictionary<Button, bool> map = new Dictionary<Button, bool>();

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.FillRectangle(Brushes.White, e.ClipRectangle);
        if (this.Site != null) return; // this code is needed otherwise designer crashes when closing
        int h = e.ClipRectangle.Height / this.Buttons.Length;
        int top = 0;
        foreach (var button in this.Buttons)
        {
            e.Graphics.FillRectangle(map[button] ? Brushes.Black : Brushes.White, new Rectangle(0, top, e.ClipRectangle.Width, h));
            top += h;
        }
        base.OnPaint(e);
    }

    void ISupportInitialize.BeginInit()
    {
    }

    void ISupportInitialize.EndInit()
    {
        if (this.Site != null) return; // this is needed so that designer does not change the colors of the buttons in design-time
        foreach (var button in this.Buttons)
        {
            button.Click += new EventHandler(button_Click);
            button.ForeColor = Color.Blue;
            map[button] = false;
        }
    }

    void button_Click(object sender, EventArgs e)
    {
        map[(Button)sender] = !map[(Button)sender];
        this.Invalidate();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在创建一个包含自定义控件的表单,在其上放置一些按钮,然后在其上放置ButtonActivityControl.自定义控件具有一个名为Buttons的属性,可以编辑.

而已!!

没有理由担心自定义编辑......而不是那么复杂......在半小时内完成它.

我认为这就是答案......也就是说,我认为是!=)也许我不太了解这个问题......但那是最好的人能做到的:试图帮助别人!

编辑

ReferencesCollectionEditor中需要此代码:

    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.Modal;
    }
    public override bool GetPaintValueSupported(ITypeDescriptorContext context)
    {
        return false;
    }
Run Code Online (Sandbox Code Playgroud)