首页 > 解决方案 > UserControl 在设计时生成子控件

问题描述

我正在尝试在 Windows 窗体中创建一个用户控件,它将具有“生成”子控件的功能。例子:

假设我们有只有flowlayoutpanel, 和 ButtonText属性的 UC:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public List<ButtonBlueprint> ButtonText { get; set; } = new List<ButtonBlueprint>();

ButtonBlueprint只是字符串的包装器,没关系:

public class ButtonBlueprint
{
    public string Name { get; set; }
}

现在,我为这个系列找到了一个不错的设计师编辑器: 在此处输入图像描述

我想要但我不知道如何实现的是从这个集合中的项目生成按钮。进入运行时很容易:

在此处输入图像描述

但我希望在设计时生成这些控件并在设计器中可见。这可能吗?我知道一些高级控件,例如来自 Telerik 的控件具有类似的功能,并且可以从类模式生成控件,所以它应该是可能的。关于如何做到这一点的任何建议?

标签: c#winformsuser-controls

解决方案


好吧,您不仅需要在设计时生成子控件,还需要通过将它们序列化为 *.Designer.cs 来保持更改。如果我很好地理解了您的问题,您可以从以下代码中获得启发。只是一个非常简单的示例(仅通过向 *.Designer.cs 添加注释来实现持久性)。

using System;
using System.CodeDom;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Windows.Forms;
using ControlDesigner = System.Windows.Forms.Design.ControlDesigner;

namespace WindowsFormsApp1
{
    [DesignerSerializer(typeof(TestSerializer), typeof(CodeDomSerializer))]
    [Designer(typeof(TestEditor), typeof(IDesigner))]
    public partial class TestControl1 : UserControl
    {
        public TestControl1()
        {
            InitializeComponent();
        }
    }

    public class TestEditor : ControlDesigner
    {
        private static int _counter;

        public TestEditor()
        {
            Verbs.Add(new DesignerVerb("Add button", Handler));
        }

        private void Handler(object sender, EventArgs e)
        {
            var button = new Button
                         {
                             Enabled = true,
                             Text = "Hello",
                             Name = string.Format("Button{0}", ++_counter)
                         };
            button.Location = new Point(0, _counter * button.Size.Height);
            ((TestControl1)Component).Controls.Add(button);
        }
    }

    public class TestSerializer : CodeDomSerializer
    {
        public override object Serialize(IDesignerSerializationManager manager, object value)
        {
            if (value.GetType() == typeof(TestControl1))
            {
                var serializer = manager.GetSerializer(typeof(TestControl1).BaseType, typeof(CodeDomSerializer)) as CodeDomSerializer;
                if (serializer != null)
                {
                    var coll = serializer.Serialize(manager, value) as CodeStatementCollection;
                    if (coll != null)
                    {
                        var tc = (TestControl1)value;
                        foreach (Control control in tc.Controls)
                        {
                            coll.Insert(0, new CodeCommentStatement("Component " + control.Name));
                        }
                    }

                    return coll;
                }
            }

            return base.Serialize(manager, value);
        }
    }
}

推荐阅读