UserControl 在设计时生成子控件
UserControl generate sub-controls at design-time
我正在尝试在 Windows 表单中创建一个用户控件,它将具有 "generating" 子控件的功能。
示例:
假设我们只有 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 的控件具有类似的功能,并且可以从 class 模式生成控件,所以它应该是可能的。关于如何做到这一点的任何建议?
好吧,您不仅需要在设计时生成子控件,还需要通过将它们序列化为 *.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);
}
}
}
我正在尝试在 Windows 表单中创建一个用户控件,它将具有 "generating" 子控件的功能。 示例:
假设我们只有 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 的控件具有类似的功能,并且可以从 class 模式生成控件,所以它应该是可能的。关于如何做到这一点的任何建议?
好吧,您不仅需要在设计时生成子控件,还需要通过将它们序列化为 *.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);
}
}
}