I am using property grid to show object properties. Dynamic properties must be shown according to conditions. I needed to show list items as a drop-down list. so I write some classes which are necessary. (please consider this list is dynamic too).
I have a custom property grid as you can see :
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);;
}
}
}
I have a class named PropertyList , This class is for adding properties to the property grid and removing properties from property grid.
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);
}
}
}
And a class for custom property
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;
}
}
}
I want to add combo box that is created from dynamic list , for this purpose I have write this code :
[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();
}
}
When I click on alphabet drop down list and choose an Item , error comes :
How Can I fix this error?
This is an old question, but I have an answer.
The options in your ComboBox are strings; you are explicitly adding them to lb.Items
in VersionTypeEditor.EditValue()
. From the question I gather that the Alphabet property must be set to an instance of VersionClass. That's the source of your error: the form is expecting a VersionClass, and the ComboBox is passing it a string.
What you need is to convert the string to a VersionClass. You have already set up a VersionConverter class and applied it to VersionClass using the TypeConverterAttribute. Now you need to add the logic for the conversion by overriding the TypeConverter.CanConvertFrom()
and TypeConverter.ConvertFrom()
methods. Here's an example (untested):
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);
}
}
Hopefully that answers your basic question. I also notice, however, that you're explicitly adding options using lb.Items.Add()
in VersionTypeEditor.EditValue()
. You can dynamically populate your ComboBox more easily by overriding more methods in VersionConverter. Specifically, you want to override TypeConverter.ConvertTo()
to take a VersionClass and return a string representation that will appear in the ComboBox, and then override TypeConverter.GetStandardValues()
to return a TypeConverter.StandardValuesCollection containing the objects that you want to appear in the ComboBox.
A lot of what I've stated here, including TypeConverter.ConvertTo()
and TypeConverter.GetStandardValues()
, is discussed in more detail on this MDSN page.