C# 如何创建用于打开表单的自定义通用PropertyGrid编辑器项?
我有一个自定义的通用表单C# 如何创建用于打开表单的自定义通用PropertyGrid编辑器项?,c#,winforms,generics,propertygrid,uitypeeditor,C#,Winforms,Generics,Propertygrid,Uitypeeditor,我有一个自定义的通用表单 public partial class MyTestForm1 : MyBrowseForm<CONTACTS_BASE> 公共部分类MyTestForm1:MyBrowseForm 其中,CONTACTS_BASE是EntityFramework实体 在父类上,我希望有一个属性,这样当我在设计器时从属性网格中单击它时,它会打开一个窗体,并且在该窗体上,我希望有一个组合框,其中填充了CONTACTS_基本实体上的字段 我找到了这个帖子 帮助我在设计时
public partial class MyTestForm1 : MyBrowseForm<CONTACTS_BASE>
公共部分类MyTestForm1:MyBrowseForm
其中,CONTACTS_BASE是EntityFramework实体
在父类上,我希望有一个属性,这样当我在设计器时从属性网格中单击它时,它会打开一个窗体,并且在该窗体上,我希望有一个组合框,其中填充了CONTACTS_基本实体上的字段
我找到了这个帖子
帮助我在设计时单击该属性时打开一个新表单,并且我还用联系人的字段填充了组合框。但为了在表单加载事件中执行此操作,我调用了一个函数,该函数返回字段列表并将其设置为ComboBox的数据源
comboBox1.DataSource = EntityBase.BaseGetTableFieldList2<CONTACTS_BASE>();
comboBox1.DataSource=EntityBase.BaseGetTableFieldList2();
然而,我想完成的是使这个通用
所以我想做的是像这样填充组合框
public partial class BdEditorForm <TParentEntity>:Form where TParentEntity:class
{
private void BdEditorForm_Load(object sender, EventArgs e)
{
comboBox1.DataSource = EntityBase.BaseGetTableFieldList2<TParentEntity>();
}
}
public分部类BdEditorForm:Form,其中TParentEntity:class
{
私有void BdEditorForm_加载(对象发送方,事件参数e)
{
comboBox1.DataSource=EntityBase.BaseGetTableFieldList2();
}
}
这样的事情可能吗?因为当我试着这么做的时候
我需要使TypeEditor也通用,然后在为我创建的属性赋予属性时
[Editor(typeof(BdFormTypeEditor<TParentEntity>), typeof(UITypeEditor))]
[TypeConverter(typeof(ExpandableObjectConverter))]
[编辑器(typeof(BdFormTypeEditor),typeof(UITypeEditor))]
[TypeConverter(typeof(ExpandableObjectConverter))]
上面写着:
感谢您的帮助,并为我糟糕的英语表达歉意简短的回答 要知道如何解决此问题,您需要知道
EditValue
方法有一个context
参数,该参数的类型为,并且有一个属性,该属性是您正在编辑的属性的所有者对象。拥有所有者(表单),我们知道表单的类型,因此我们知道泛型参数类型,因此我们可以创建泛型编辑器表单
逐步示例
以上事实是答案的关键,但要解决这个问题,你还需要应用一些其他技巧。例如,您应该获取泛型类型并使用反射创建其实例
在这里,我放置了一个包含示例的全部源代码的项目:
MyBaseForm
派生的表单的特定属性时,该编辑器将显示T
的属性列表
通用基本表单
它是包含SomeProperty
的其他表单的基本表单,您要使用自定义编辑器编辑该属性
将MyGenericType
属性添加到返回typeof(T)
的类中,该类是表单的泛型类型:
public partial class MyBaseForm<T> : Form
{
public MyBaseForm()
{
InitializeComponent();
}
[Editor(typeof(MyUITypeEditor), typeof(UITypeEditor))]
public string SomeProperty { get; set; }
[Browsable(false)]
public Type MyGenericType { get { return typeof(T); } }
}
样本模型
这是一个示例模型,我们将在自定义编辑器窗口中显示它的属性
public class MySampleModel
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
}
编辑表单
它是UITypeEditor
将显示的表单。在表单中,我们用泛型参数的字段名填充combox1
public partial class MyEditorForm<T> : Form
{
public MyEditorForm()
{
InitializeComponent();
this.StartPosition = FormStartPosition.CenterScreen;
var list = ListBindingHelper.GetListItemProperties(typeof(T))
.Cast<PropertyDescriptor>()
.Select(x => new { Text = x.Name, Value = x }).ToList();
this.comboBox1.DataSource = list;
this.comboBox1.DisplayMember = "Text";
this.comboBox1.ValueMember = "Value";
}
public string SelectedProperty
{
get
{
return comboBox1.GetItemText(comboBox1.SelectedItem);
}
}
private void button1_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
}
}
作为旁注,请记住,如果您的目标只是选择
T
的一个属性,那么也有更简单的选项。但是我发布了答案和完整的学习示例,其中包含一些有用的技巧,包括使用上下文
,使用反射创建动态类型的实例,在组合框中显示属性等等:)注意上下文
是(在属性网格版的上下文中)仅是GridItem
的一个实例,它是一个公共类:。即使没有此选项,ITypeScriptorContext
也有一个实例
属性,它是组件实例。无需使用反射。@SimonMourier谢谢您的评论。关于实例属性,我知道该属性,并且已经使用过它。可能是在编写示例时,由于代码中的错误,我改变了主意。我再次将代码更改为使用instance
属性。关于类型,是的,您提到的类型是我使用的类型的基础,我使用它只是因为Component
property。不再使用它了。谢谢你的评论:)@RezaAghaei工作得很好=)我还有一个问题:当我打开BdEditor表单时,我会在列表中输入多个信息。我返回列表,我想做的是将该列表传递到BdEditor,这样,如果列表不是空的,我就可以添加更多的项以从中删除。我该怎么做?这可能吗?你看过我的答案了吗?我想这就是你要找的。
public partial class MyEditorForm<T> : Form
{
public MyEditorForm()
{
InitializeComponent();
this.StartPosition = FormStartPosition.CenterScreen;
var list = ListBindingHelper.GetListItemProperties(typeof(T))
.Cast<PropertyDescriptor>()
.Select(x => new { Text = x.Name, Value = x }).ToList();
this.comboBox1.DataSource = list;
this.comboBox1.DisplayMember = "Text";
this.comboBox1.ValueMember = "Value";
}
public string SelectedProperty
{
get
{
return comboBox1.GetItemText(comboBox1.SelectedItem);
}
}
private void button1_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
}
}
public class MyUITypeEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
var svc = provider.GetService(typeof(IWindowsFormsEditorService))
as IWindowsFormsEditorService;
var myGenericTypeProperty = context.Instance.GetType()
.GetProperty("MyGenericType");
var genericArgument = (Type)myGenericTypeProperty.GetValue(context.Instance);
var editorFormType = typeof(MyEditorForm<>);
var genericArguments = new[] { genericArgument };
var editorFormInstance = editorFormType.MakeGenericType(genericArguments);
if (svc != null)
{
using (var f = (Form)Activator.CreateInstance(editorFormInstance))
if (svc.ShowDialog(f) == DialogResult.OK)
return ((dynamic)f).SelectedProperty;
}
else
{
using (var f = (Form)Activator.CreateInstance(editorFormInstance))
if (f.ShowDialog() == DialogResult.OK)
return ((dynamic)f).SelectedProperty;
}
return base.EditValue(context, provider, value);
}
}