[英]How to create custom generic PropertyGrid editor item which opens a form?
我有一個自定義的通用表單
public partial class MyTestForm1 : MyBrowseForm<CONTACTS_BASE>
其中 CONTACTS_BASE 是一個 EntityFramework 實體。
在父類上,我想要一個屬性,這樣當我在設計器時從屬性網格中單擊它時,它會打開一個表單,在該表單上我想要一個組合框,其中包含 CONTACTS_BASE 實體上的字段。
我發現這篇文章Marc Gravell 的回答幫助我在設計時單擊屬性時打開了一個新表單,並且我還使用 CONTACTS_BASE 字段填充了 ComboBox。 但要在表單加載事件上執行此操作,我調用了我所做的函數,該函數返回字段列表並將其設置為 ComboBox 的數據源。
comboBox1.DataSource = EntityBase.BaseGetTableFieldList2<CONTACTS_BASE>();
但是我想完成的是使這個通用
所以我想做的是這樣的事情來填充 ComboBox。
public partial class BdEditorForm <TParentEntity>:Form where TParentEntity:class
{
private void BdEditorForm_Load(object sender, EventArgs e)
{
comboBox1.DataSource = EntityBase.BaseGetTableFieldList2<TParentEntity>();
}
}
這樣的事情可能嗎? 因為當我嘗試這樣做時,我也需要使 TypeEditor 通用,然后在為我創建的屬性賦予屬性時
[Editor(typeof(BdFormTypeEditor<TParentEntity>), typeof(UITypeEditor))]
[TypeConverter(typeof(ExpandableObjectConverter))]
任何幫助表示感謝感謝和抱歉我的英語不好
簡答
要知道如何解決這個問題,您需要知道EditValue
方法有一個context
參數,它是ITypeDescriptorContext
類型,並且有一個Instance
屬性,它是您正在編輯的屬性的所有者對象。 擁有所有者(表單),我們知道表單的類型,因此我們知道通用參數類型,因此我們可以創建我們的通用編輯器表單。
分步示例
以上事實是答案的關鍵點,但要解決問題,您還需要應用一些其他技巧。 例如,您應該獲得一個泛型類型並使用反射創建它的一個實例。
這里我放了一個項目,其中包含示例的整個源代碼:
以下是示例的步驟,該示例創建自定義模型 UI 類型編輯器,以在您編輯從MyBaseForm<T>
派生的表單的特定屬性時顯示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); } }
}
派生形式
它是派生自MyBaseForm<T>
的示例派生形式。 我們將編輯此類實例的SomeProperty
。
public partial class MyDerivedForm : MyBaseForm<MySampleModel>
{
public MyDerivedForm()
{
InitializeComponent();
}
}
示例模型
這是一個示例模型,我們將在自定義編輯器窗口中顯示其屬性。
public class MySampleModel
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
}
編輯表格
這是UITypeEditor
將顯示的表單。 在表單中,我們用通用參數的字段名稱填充comoBox1
。
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;
}
}
UI 類型編輯器
調用UITypeEditor
EditValue
方法時, context
參數的類型為System.Windows.Forms.PropertyGridInternal.PropertyDescriptorGridEntry
,它有一個Component
屬性,其值是您正在編輯的表單的實例,因此我們知道表單的類型因此我們知道通用參數類型,因此我們可以創建我們的通用編輯器表單並使用它。
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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.