属性 'System.String' 类型的网格对象无法转换为 'x' 类型
property grid Object of type 'System.String' cannot be converted to type 'x'
我正在使用 属性 网格来显示对象属性。必须根据条件显示动态属性。我需要将列表项显示为下拉列表。
所以我写了一些必要的 classes。 (请考虑此列表也是动态的)。
我有一个自定义的 属性 网格,如您所见:
public class myPropertyGrid : PropertyGrid
{
private System.ComponentModel.Container components = null;
public myPropertyGrid()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Codice generato da Progettazione componenti
/// <summary>
/// Metodo necessario per il supporto della finestra di progettazione. Non modificare
/// il contenuto del metodo con l'editor di codice.
/// </summary>
private void InitializeComponent()
{
//
// UserControl1
//
this.Name = "myPropertyGrid";
}
#endregion
protected override PropertyTab CreatePropertyTab(Type tabType)
{
myTab t = new myTab();
return t;
}
}
public class myTab : PropertyTab
{
public myTab()
{
}
// get the properties of the selected component
public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, System.Attribute[] attributes)
{
PropertyDescriptorCollection properties;
if(attributes!=null)
properties=TypeDescriptor.GetProperties(component,attributes);
else
properties=TypeDescriptor.GetProperties(component);
//Componet must implement the ICUSTOMCLASS interface.
ICustomClass bclass=(ICustomClass)component;
//The new array of properties, based on the PublicProperties properties of "model"
PropertyDescriptor[] arrProp = new PropertyDescriptor[bclass.PublicProperties.Count];
for (int i=0;i<bclass.PublicProperties.Count;i++)
{
//Find the properties in the array of the propertis which neme is in the PubliCProperties
PropertyDescriptor prop=properties.Find(bclass.PublicProperties[i].Name,true);
//Build a new properties
arrProp[i] = TypeDescriptor.CreateProperty(prop.ComponentType, prop, new CategoryAttribute("جزئیات"));
}
return new PropertyDescriptorCollection(arrProp);
}
public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component)
{
return this.GetProperties(component,null);
}
// PropertyTab Name
public override string TabName
{
get
{
return "Properties";
}
}
//Image of the property tab (return a blank 16x16 Bitmap)
public override System.Drawing.Bitmap Bitmap
{
get
{
return new Bitmap(16,16);;
}
}
}
我有一个名为 PropertyList 的 class,这个 class 用于向 属性 网格添加属性并从 属性 网格。
public class PropertyList : NameObjectCollectionBase
{
public void Add(Object value)
{
//The key for the object is taken from the object to insert
this.BaseAdd(((CustomProperty)value).Name, value);
}
public void Remove(String key)
{
this.BaseRemove(key);
}
public void Remove(int index)
{
this.BaseRemoveAt(index);
}
public void Clear()
{
this.BaseClear();
}
public CustomProperty this[String key]
{
get
{
return (CustomProperty)(this.BaseGet(key));
}
set
{
this.BaseSet(key, value);
}
}
public CustomProperty this[int indice]
{
get
{
return (CustomProperty)(this.BaseGet(indice));
}
set
{
this.BaseSet(indice, value);
}
}
}
还有一个 class 用于自定义 属性
public class CustomProperty
{
private string sName = string.Empty;
private bool bReadOnly = false;
private bool bVisible = true;
private object objValue = null;
private object tag = null;
private string displayName = string.Empty;
public CustomProperty(object tag, string sName, object value, Type type, bool bReadOnly, bool bVisible)
{
this.tag = tag;
this.sName = sName;
this.objValue = value;
this.type = type;
this.bReadOnly = bReadOnly;
this.bVisible = bVisible;
}
public CustomProperty(object tag, string displayName, string sName, object value, Type type, bool bReadOnly, bool bVisible)
:this(tag,sName,value,type,bReadOnly,bVisible)
{
this.displayName = displayName;
}
private Type type;
public Type Type
{
get { return type; }
}
public bool ReadOnly
{
get
{
return bReadOnly;
}
}
public string Name
{
get
{
return sName;
}
set
{
sName = value;
}
}
public bool Visible
{
get
{
return bVisible;
}
}
public object Value
{
get
{
return objValue;
}
set
{
objValue = value;
}
}
public object Tag
{
get
{
return tag;
}
set
{
tag = value;
}
}
public string DisplayName
{
get
{
return displayName;
}
set
{
displayName = value;
}
}
}
我想添加从动态列表创建的组合框,为此我编写了以下代码:
[TypeConverter(typeof(VersionConvertor))]
[Editor(typeof(VersionTypeEditor), typeof(UITypeEditor))]
public class VersionClass
{
public VersionClass()
{
}
}
public class VersionConvertor : TypeConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
}
public class VersionTypeEditor : UITypeEditor
{
private IWindowsFormsEditorService _editorService;
private ListBox lb;
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
// drop down mode (we'll host a listbox in the drop down)
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
_editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
// use a list box
lb = new ListBox();
lb.SelectionMode = SelectionMode.One;
lb.SelectedValueChanged += OnListBoxSelectedValueChanged;
lb.DisplayMember = "Name";
List<string> listItem = new List<string>();
listItem.Add("a"); // assume that these items are added dynamically
listItem.Add("b");
foreach (string item in listItem)
{
lb.Items.Add(item);
}
lb.SelectedItem = listItem[0];
lb.ValueMember = listItem[0];
_editorService.DropDownControl(lb);
if (lb.SelectedItem == null) // no selection, return the passed-in value as is
return value;
return lb.SelectedItem;
}
private void OnListBoxSelectedValueChanged(object sender, EventArgs e)
{
lb.SelectedItem = ((ListBox)(sender)).SelectedItem;
_editorService.CloseDropDown();
}
}
当我点击字母表下拉列表并选择一个项目时,出现错误:
如何修复此错误?
这是一个老问题,但我有一个答案。
ComboBox 中的选项是字符串;您明确将它们添加到 VersionTypeEditor.EditValue()
中的 lb.Items
。从我收集到的问题中,Alphabet 属性 必须设置为 VersionClass 的一个实例。这就是错误的根源:表单需要一个 VersionClass,而 ComboBox 正在向它传递一个字符串。
您需要将字符串转换为 VersionClass。您已经设置了 VersionConverter class 并使用 TypeConverterAttribute 将其应用于 VersionClass。现在您需要通过覆盖 TypeConverter.CanConvertFrom()
和 TypeConverter.ConvertFrom()
方法来添加转换逻辑。这是一个示例(未经测试):
public class VersionConverter : TypeConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (type == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
// conversion logic goes here
return convertedVersionClass;
}
return base.ConvertFrom(context, culture, value);
}
}
希望这能回答您的基本问题。但是,我还注意到您在 VersionTypeEditor.EditValue()
中使用 lb.Items.Add()
明确添加了选项。通过覆盖 VersionConverter 中的更多方法,您可以更轻松地动态填充 ComboBox。具体来说,您想覆盖 TypeConverter.ConvertTo()
以获取 VersionClass 和 return 将出现在 ComboBox 中的字符串表示形式,然后将 TypeConverter.GetStandardValues()
覆盖为 return a TypeConverter.StandardValuesCollection 包含您希望在 ComboBox 中显示的对象。
我在这里陈述的很多内容,包括 TypeConverter.ConvertTo()
和 TypeConverter.GetStandardValues()
,在 this MDSN page 上有更详细的讨论。
我正在使用 属性 网格来显示对象属性。必须根据条件显示动态属性。我需要将列表项显示为下拉列表。 所以我写了一些必要的 classes。 (请考虑此列表也是动态的)。
我有一个自定义的 属性 网格,如您所见:
public class myPropertyGrid : PropertyGrid
{
private System.ComponentModel.Container components = null;
public myPropertyGrid()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Codice generato da Progettazione componenti
/// <summary>
/// Metodo necessario per il supporto della finestra di progettazione. Non modificare
/// il contenuto del metodo con l'editor di codice.
/// </summary>
private void InitializeComponent()
{
//
// UserControl1
//
this.Name = "myPropertyGrid";
}
#endregion
protected override PropertyTab CreatePropertyTab(Type tabType)
{
myTab t = new myTab();
return t;
}
}
public class myTab : PropertyTab
{
public myTab()
{
}
// get the properties of the selected component
public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, System.Attribute[] attributes)
{
PropertyDescriptorCollection properties;
if(attributes!=null)
properties=TypeDescriptor.GetProperties(component,attributes);
else
properties=TypeDescriptor.GetProperties(component);
//Componet must implement the ICUSTOMCLASS interface.
ICustomClass bclass=(ICustomClass)component;
//The new array of properties, based on the PublicProperties properties of "model"
PropertyDescriptor[] arrProp = new PropertyDescriptor[bclass.PublicProperties.Count];
for (int i=0;i<bclass.PublicProperties.Count;i++)
{
//Find the properties in the array of the propertis which neme is in the PubliCProperties
PropertyDescriptor prop=properties.Find(bclass.PublicProperties[i].Name,true);
//Build a new properties
arrProp[i] = TypeDescriptor.CreateProperty(prop.ComponentType, prop, new CategoryAttribute("جزئیات"));
}
return new PropertyDescriptorCollection(arrProp);
}
public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component)
{
return this.GetProperties(component,null);
}
// PropertyTab Name
public override string TabName
{
get
{
return "Properties";
}
}
//Image of the property tab (return a blank 16x16 Bitmap)
public override System.Drawing.Bitmap Bitmap
{
get
{
return new Bitmap(16,16);;
}
}
}
我有一个名为 PropertyList 的 class,这个 class 用于向 属性 网格添加属性并从 属性 网格。
public class PropertyList : NameObjectCollectionBase
{
public void Add(Object value)
{
//The key for the object is taken from the object to insert
this.BaseAdd(((CustomProperty)value).Name, value);
}
public void Remove(String key)
{
this.BaseRemove(key);
}
public void Remove(int index)
{
this.BaseRemoveAt(index);
}
public void Clear()
{
this.BaseClear();
}
public CustomProperty this[String key]
{
get
{
return (CustomProperty)(this.BaseGet(key));
}
set
{
this.BaseSet(key, value);
}
}
public CustomProperty this[int indice]
{
get
{
return (CustomProperty)(this.BaseGet(indice));
}
set
{
this.BaseSet(indice, value);
}
}
}
还有一个 class 用于自定义 属性
public class CustomProperty
{
private string sName = string.Empty;
private bool bReadOnly = false;
private bool bVisible = true;
private object objValue = null;
private object tag = null;
private string displayName = string.Empty;
public CustomProperty(object tag, string sName, object value, Type type, bool bReadOnly, bool bVisible)
{
this.tag = tag;
this.sName = sName;
this.objValue = value;
this.type = type;
this.bReadOnly = bReadOnly;
this.bVisible = bVisible;
}
public CustomProperty(object tag, string displayName, string sName, object value, Type type, bool bReadOnly, bool bVisible)
:this(tag,sName,value,type,bReadOnly,bVisible)
{
this.displayName = displayName;
}
private Type type;
public Type Type
{
get { return type; }
}
public bool ReadOnly
{
get
{
return bReadOnly;
}
}
public string Name
{
get
{
return sName;
}
set
{
sName = value;
}
}
public bool Visible
{
get
{
return bVisible;
}
}
public object Value
{
get
{
return objValue;
}
set
{
objValue = value;
}
}
public object Tag
{
get
{
return tag;
}
set
{
tag = value;
}
}
public string DisplayName
{
get
{
return displayName;
}
set
{
displayName = value;
}
}
}
我想添加从动态列表创建的组合框,为此我编写了以下代码:
[TypeConverter(typeof(VersionConvertor))]
[Editor(typeof(VersionTypeEditor), typeof(UITypeEditor))]
public class VersionClass
{
public VersionClass()
{
}
}
public class VersionConvertor : TypeConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
}
public class VersionTypeEditor : UITypeEditor
{
private IWindowsFormsEditorService _editorService;
private ListBox lb;
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
// drop down mode (we'll host a listbox in the drop down)
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
_editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
// use a list box
lb = new ListBox();
lb.SelectionMode = SelectionMode.One;
lb.SelectedValueChanged += OnListBoxSelectedValueChanged;
lb.DisplayMember = "Name";
List<string> listItem = new List<string>();
listItem.Add("a"); // assume that these items are added dynamically
listItem.Add("b");
foreach (string item in listItem)
{
lb.Items.Add(item);
}
lb.SelectedItem = listItem[0];
lb.ValueMember = listItem[0];
_editorService.DropDownControl(lb);
if (lb.SelectedItem == null) // no selection, return the passed-in value as is
return value;
return lb.SelectedItem;
}
private void OnListBoxSelectedValueChanged(object sender, EventArgs e)
{
lb.SelectedItem = ((ListBox)(sender)).SelectedItem;
_editorService.CloseDropDown();
}
}
当我点击字母表下拉列表并选择一个项目时,出现错误:
如何修复此错误?
这是一个老问题,但我有一个答案。
ComboBox 中的选项是字符串;您明确将它们添加到 VersionTypeEditor.EditValue()
中的 lb.Items
。从我收集到的问题中,Alphabet 属性 必须设置为 VersionClass 的一个实例。这就是错误的根源:表单需要一个 VersionClass,而 ComboBox 正在向它传递一个字符串。
您需要将字符串转换为 VersionClass。您已经设置了 VersionConverter class 并使用 TypeConverterAttribute 将其应用于 VersionClass。现在您需要通过覆盖 TypeConverter.CanConvertFrom()
和 TypeConverter.ConvertFrom()
方法来添加转换逻辑。这是一个示例(未经测试):
public class VersionConverter : TypeConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (type == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
// conversion logic goes here
return convertedVersionClass;
}
return base.ConvertFrom(context, culture, value);
}
}
希望这能回答您的基本问题。但是,我还注意到您在 VersionTypeEditor.EditValue()
中使用 lb.Items.Add()
明确添加了选项。通过覆盖 VersionConverter 中的更多方法,您可以更轻松地动态填充 ComboBox。具体来说,您想覆盖 TypeConverter.ConvertTo()
以获取 VersionClass 和 return 将出现在 ComboBox 中的字符串表示形式,然后将 TypeConverter.GetStandardValues()
覆盖为 return a TypeConverter.StandardValuesCollection 包含您希望在 ComboBox 中显示的对象。
我在这里陈述的很多内容,包括 TypeConverter.ConvertTo()
和 TypeConverter.GetStandardValues()
,在 this MDSN page 上有更详细的讨论。