如何在 PropertyGrid 自定义 collection 编辑器中自定义 "Add" 按钮下拉列表中的名称
How to customize names in "Add" button dropdown in the PropertyGrid custom collection editor
我正在使用 PropertyGrid 编辑 collection。带有 collection 的 object 定义如下:
class ObjWithCollection
{
[Editor(typeof(MyCustomCollectionEditor),typeof(UITypeEditor))]
public List<ItemBase> collection { get; set; } = new List<ItemBase>();//ItemBase is abstract
}
collection包含两种类型的object,派生自ItemBaseclass:Item1 和 项目 2。这些 class 定义如下:
public abstract class ItemBase
{
public string Name { get; set; }
public ItemBase() { }
public ItemBase(string name) { Name = name; }
}
public class Item1:ItemBase
{
public Item1():base("Item 1 name"){}
}
[DisplayName("item2 test display name")]
public class Item2:ItemBase
{
public Item2() : base("item 2 name") { }
}
为了能够通过编辑器向 collection 添加新项目,我还定义了自定义 collection 编辑器 class 并覆盖 CreateNewItemTypes 列出适合 collection 的所有类型:
class MyCustomCollectionEditor : CollectionEditor
{
public MyCustomCollectionEditor(Type type) : base(type){}
protected override Type[] CreateNewItemTypes()
{
return new Type[] { typeof(Item1), typeof(Item2) };
}
}
然后我将自定义编辑器绑定到 ObjWithCollection.collection 属性 和 Editor 属性(参见 ObjWithCollection.collection 定义).
这很好用,我可以编辑我的 collection,包括添加新项目。添加按钮有一个下拉菜单,允许用户 select 要添加的元素类型。
editor window http://i.share.pho.to/31d50d09_o.png
但是在“添加”按钮下拉列表中,名为“Item1”和“Item2”的项目我无法更改这些名称。我尝试了 DisplayName 属性,ToString 覆盖,但没有成功。
所以,问题是如何输出 Add 按钮菜单元素的自定义名称。
我认为这不可能直接从 属性 网格的代码中实现。但是,您可以使用 TypeDelegator 来欺骗系统并强制它使用例如您的 DisplayName 属性来代替它默认使用的类型名称 属性。
1) 创建自定义 TypeDelegator,如下所示:
class MyTypeDelegator : TypeDelegator
{
public MyTypeDelegator(Type delegatingType)
: base(delegatingType)
{
}
public override string Name
{
get
{
var dna = (DisplayNameAttribute)typeImpl.GetCustomAttribute(typeof(DisplayNameAttribute));
return dna != null ? dna.DisplayName : typeImpl.Name;
}
}
}
2) 像这样修改 CreateNewItemTypes():
protected override Type[] CreateNewItemTypes()
{
return new Type[] { new MyTypeDelegator(typeof(Item1)), new MyTypeDelegator(typeof(Item2)) };
}
现在,您应该在菜单中看到显示名称而不是名称。
您还可以通过连接到 CollectionForm 的控件来更改文本(丑陋,不推荐,请勿在生产中使用,请注意它可能随时更改和过时)
public sealed class OutputItemEditor : CollectionEditor // need a reference to System.Design.dll
{
public OutputItemEditor(Type type)
: base(type)
{
}
protected override Type[] CreateNewItemTypes()
{
return new[] { typeof(StaticOutputItem), typeof(VariableOutputItem),typeof(ExpressionOutputItem) };
}
protected override CollectionForm CreateCollectionForm()
{
CollectionForm collectionForm = base.CreateCollectionForm();
collectionForm.Text = "Output Collection";
//Modify the Add Item Button Text
try
{
//You can use "collectionForm.Controls.Find("addButton",true)" here also
foreach (ToolStripItem item in collectionForm.Controls[0].Controls[1].Controls[0].ContextMenuStrip.Items)
{
//Since Item Names are the Type Names
switch (item.Text)
{
case "StaticOutputItem":
item.Text = "Static Output Item";
break;
case "VariableOutputItem":
item.Text = "Variable Output Item";
break;
case "ExpressionOutputItem":
item.Text = "Expression Output Item";
break;
default:
break;
}
}
}
catch (Exception)
{
}
return collectionForm;
}
}
我正在使用 PropertyGrid 编辑 collection。带有 collection 的 object 定义如下:
class ObjWithCollection
{
[Editor(typeof(MyCustomCollectionEditor),typeof(UITypeEditor))]
public List<ItemBase> collection { get; set; } = new List<ItemBase>();//ItemBase is abstract
}
collection包含两种类型的object,派生自ItemBaseclass:Item1 和 项目 2。这些 class 定义如下:
public abstract class ItemBase
{
public string Name { get; set; }
public ItemBase() { }
public ItemBase(string name) { Name = name; }
}
public class Item1:ItemBase
{
public Item1():base("Item 1 name"){}
}
[DisplayName("item2 test display name")]
public class Item2:ItemBase
{
public Item2() : base("item 2 name") { }
}
为了能够通过编辑器向 collection 添加新项目,我还定义了自定义 collection 编辑器 class 并覆盖 CreateNewItemTypes 列出适合 collection 的所有类型:
class MyCustomCollectionEditor : CollectionEditor
{
public MyCustomCollectionEditor(Type type) : base(type){}
protected override Type[] CreateNewItemTypes()
{
return new Type[] { typeof(Item1), typeof(Item2) };
}
}
然后我将自定义编辑器绑定到 ObjWithCollection.collection 属性 和 Editor 属性(参见 ObjWithCollection.collection 定义).
这很好用,我可以编辑我的 collection,包括添加新项目。添加按钮有一个下拉菜单,允许用户 select 要添加的元素类型。 editor window http://i.share.pho.to/31d50d09_o.png
但是在“添加”按钮下拉列表中,名为“Item1”和“Item2”的项目我无法更改这些名称。我尝试了 DisplayName 属性,ToString 覆盖,但没有成功。
所以,问题是如何输出 Add 按钮菜单元素的自定义名称。
我认为这不可能直接从 属性 网格的代码中实现。但是,您可以使用 TypeDelegator 来欺骗系统并强制它使用例如您的 DisplayName 属性来代替它默认使用的类型名称 属性。
1) 创建自定义 TypeDelegator,如下所示:
class MyTypeDelegator : TypeDelegator
{
public MyTypeDelegator(Type delegatingType)
: base(delegatingType)
{
}
public override string Name
{
get
{
var dna = (DisplayNameAttribute)typeImpl.GetCustomAttribute(typeof(DisplayNameAttribute));
return dna != null ? dna.DisplayName : typeImpl.Name;
}
}
}
2) 像这样修改 CreateNewItemTypes():
protected override Type[] CreateNewItemTypes()
{
return new Type[] { new MyTypeDelegator(typeof(Item1)), new MyTypeDelegator(typeof(Item2)) };
}
现在,您应该在菜单中看到显示名称而不是名称。
您还可以通过连接到 CollectionForm 的控件来更改文本(丑陋,不推荐,请勿在生产中使用,请注意它可能随时更改和过时)
public sealed class OutputItemEditor : CollectionEditor // need a reference to System.Design.dll
{
public OutputItemEditor(Type type)
: base(type)
{
}
protected override Type[] CreateNewItemTypes()
{
return new[] { typeof(StaticOutputItem), typeof(VariableOutputItem),typeof(ExpressionOutputItem) };
}
protected override CollectionForm CreateCollectionForm()
{
CollectionForm collectionForm = base.CreateCollectionForm();
collectionForm.Text = "Output Collection";
//Modify the Add Item Button Text
try
{
//You can use "collectionForm.Controls.Find("addButton",true)" here also
foreach (ToolStripItem item in collectionForm.Controls[0].Controls[1].Controls[0].ContextMenuStrip.Items)
{
//Since Item Names are the Type Names
switch (item.Text)
{
case "StaticOutputItem":
item.Text = "Static Output Item";
break;
case "VariableOutputItem":
item.Text = "Variable Output Item";
break;
case "ExpressionOutputItem":
item.Text = "Expression Output Item";
break;
default:
break;
}
}
}
catch (Exception)
{
}
return collectionForm;
}
}