views:

36

answers:

3

I am trying to use property grid for displaying data. I have to write StringConverters for my predefined string constants so that they can be shown on a combo box.

Consider a list of colors and another list of angles 0,90,180,270. There are many such lists I want to display on the grid.

I am writing new classes deriving from StringConverters and overriding GetStandardValues

class AngleConverter : StringConverter
{
    string[] Units = { "0", "90", "180","270" };
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return true;
    }
    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        return new StandardValuesCollection(Units);
    }
    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    {
        return true;
    }
}

Class UnitConverter : ... Same code except change in the string array. I use this Class before the property like [TypeConverter(typeof(AngleConverter))]. I need to create new class if I want to add a string list to be displayed in a list box on the grid.

Is there a generic way of doing this without creating new classes everytime.

Thanks --Hari

+1  A: 

EDIT: According to Thomas Lycken's answer at this link, it might help if your properties are enums...

I don't know if you can avoid writing new classes or not. I am not familiar enough with what you are doing to know if there is a significantly better or easier way or not. Having said that, you could shorten your class somewhat by making an abstract base class something like this:

class MyBaseStringConverter : StringConverter 
{ 
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context) 
    { 
        return true; 
    } 
    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) 
    { 
        //Call the abstract GetValues function here.
        return new StandardValuesCollection(GetValues()); 
    } 
    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) 
    { 
        return true; 
    } 
    protected abstract string [] GetValues();
} 

public AngleConverter : MyBaseStringConverter
{
  protected override string [] GetValues() 
  { 
    return new string [] { "0", "90", "180", "270" };
  }
}

public ColorConverter : MyBaseStringConverter
{
  protected override string [] GetValues()
  {
    return new string [] { "Red", "Green", "Blue" };
  }
}
wageoghe
A: 

Alternatively you can use ObjectDataProvider.

Of course, if I understand correctly what you want.

See also: Binding to enumeration.

JohnKZ
A: 

Well, I would write another attribute to contain the standard values. Then your StringConverter derived class would simply detect this attribute and grab the values from there:

private string _unit = "m/s";

[PropertyValueDisplayedAs(new string[] { "m/s", "km/h" })]
[TypeConverter(typeof(MyStringConverter))]
public string ConstraintString
{
    get { return _unit; }
    set { _unit = value; }
}

Your converter would look like:

public class MyStringConverter : StringConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        PropertyValueDisplayedAsAttribute attr = (PropertyValueDisplayedAsAttribute)context.PropertyDescriptor.Attributes[typeof(PropertyValueDisplayedAsAttribute)];
        return new StandardValuesCollection(attr.DisplayedValues);
    }
}

Of course you could cache the standard values in the converter to avoid requesting them if they don't change per property. I'll let you write PropertyValueDisplayedAsAttribute wich is a very simple attribute holding a collection.

Nicolas Cadilhac