2011-09-14 15 views
12

Mam siatkę właściwości, z której korzystam, aby użytkownicy mogli konfigurować obiekty dla dowolnej wtyczki zapisanej do użycia w mojej aplikacji. Chciałbym móc powiedzieć programistom pisanie wtyczek używać ComponentModel Atrybuty dla swoich członków tak:Edytowanie wyświetlanej nazwy elementów wyliczeniowych w obiekcie PropertyGrid

[CategoryAttribute("On Screen Display Settings"), 
DescriptionAttribute("Whether or not to show the session timer."), 
DisplayName("Show Session Timer")] 
public bool ShowTimer 
{ 
    get; 
    set; 
} 

to działa świetnie. Teraz chciałbym, aby członkowie wyliczenia również mogli być edytowani. tj

public enum Resolution_ : byte 
{ 
    DCIF, 
    CIF, 
    QCIF, 
    [DisplayName("4CIF")] 
    CIF4, 
    [DisplayName("2CIF")] 
    CIF2 
} 

więc, że są one wyświetlane na liście PropertyGrid jest tak:

DCIF 
CIF 
QCIF 
CIF4 
CIF2 

wraz z wszelkimi opisami i nazwami wyświetlaczu mogą one mieć z nimi.

Wygląda na to, że mogę to zrobić tylko dzięki właściwościom, zdarzeniom i metodom. Czy ktoś wie, jak mogę to zrobić dla wyliczenia?

Odpowiedz

14

Będziesz musiał wykonać klasę EnumConverter i udekorować swoją nieruchomość atrybutem TypeConverter, aby to zrobić.

Zobacz ten Using PropertyGrid in .NET, to zabawa przykład:

Wyobraź sobie, że chcesz więcej niż dwie pozycje w liście. Typ boolowski to za mało; musisz ustawić atrybuty opisu z nazwą dla każdego elementu w enum.

enum DrinkDoses { 
    [Description("Half of litre")] 
    litre, 
    [Description("One litre")] 
    oneLitre, 
    [Description("Two litres")] 
    twoLitre, 
    [Description("Three litres")] 
    threeLitres, 
    [Description("Four litres")] 
    fourLitres, 
    [Description("Death dose, five litres")] 
    fiveLitres 
} 

W innej klasie trzeba wykorzystać typ EnumConverter.

class DrinkDosesConverter : EnumConverter { 
    private Type enumType; 

    public DrinkDosesConverter(Type type) : base(type) { 
    enumType = type; 
    } 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) { 
    return destType == typeof(string); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, 
            object value, Type destType) { 
    FieldInfo fi = enumType.GetField(Enum.GetName(enumType, value)); 
    DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, 
           typeof(DescriptionAttribute)); 
    if (dna != null) 
     return dna.Description; 
    else 
     return value.ToString(); 
    } 

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type srcType) { 
    return srcType == typeof(string); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, 
            object value) { 
    foreach (FieldInfo fi in enumType.GetFields()) { 
     DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, 
            typeof(DescriptionAttribute)); 
     if ((dna != null) && ((string)value == dna.Description)) 
     return Enum.Parse(enumType, fi.Name); 
    } 
    return Enum.Parse(enumType, (string)value); 
    } 
} 

Po trzecie, trzeba ustawić TypeConverter atrybutu do wyświetlania właściwości.

class DrinkerDoses { 
    DrinkDoses doses; 
    [DisplayName("Doses")] 
    [Description("Drinker doses")] 
    [Category("Alcoholics drinking")] 
    [TypeConverter(typeof(DrinkDosesConverter))] 
    public DrinkDoses Doses { 
    get { return doses; } 
    set { doses = value; } 
    } 
    int dataInt; 
    public int DataInt { 
    get { return dataInt; } 
    set { dataInt = value; } 
    } 
} 
+0

Dzięki! to było to. Nie wiem dlaczego, ale godzinę z Google i nadal nie znalazłem tego artykułu. –

+0

Miło, nie spotkałem EnumConvertera w moich bitwach z PropertyGrid wcześniej. –

+0

Hiperłącze "Używanie PropertyGrid w .NET" nie jest poprawne. –

3

Możesz dołączyć zwyczaj TypeConverter wdrożenie do właściwości, której typ jest Twój wyliczenie i zastąpić GetStandardValuesSupported i GetStandardValues wrócić niestandardową listę elementów, które można wyświetlić na liście rozwijanej w PropertyGrid. Następnie można zastąpić metody ConvertFrom/ConvertTo, aby obsłużyć konwersję wartości do/z twojego typu wyliczeniowego.

Możesz również zastąpić GetStandardValuesExclusive i przywrócić "true", aby użytkownik nie mógł niczego wpisać w wartość właściwości.

Tak, coś takiego:

public class MyTypeConverter : TypeConverter 
{ 
    //Override GetStandardValuesExclusive, 
    //GetStandardValues and GetStandardValuesSupported 
} 

public class SomeClass 
{ 
    [TypeConverter(typeof(MyTypeConverter))] 
    public Resolution SomePropertry 
    { 
     ... 
    } 
} 

W swojej realizacji GetStandardValues ​​/ ConvertFrom/ConvertTo można następnie użyć refleksji wyciągnąć DisplayNameAttribute (lub DescriptionAttribute, które mogą być bardziej nadaje się do tego zadania) Atrybuty różnych członków enum, aby pokazać ten tekst zamiast twardego kodowania listy przedmiotów do pokazania.

4

Odpowiedź podałem here ma działający przykład tego.Oto specyficzny kod z tego przykładu, że chcesz:

/// <summary> 
/// This attribute is used to represent a string value 
/// for a value in an enum. 
/// </summary> 
public class StringValueAttribute : Attribute { 

    #region Properties 

    /// <summary> 
    /// Holds the stringvalue for a value in an enum. 
    /// </summary> 
    public string StringValue { get; protected set; } 

    #endregion 

    #region Constructor 

    /// <summary> 
    /// Constructor used to init a StringValue Attribute 
    /// </summary> 
    /// <param name="value"></param> 
    public StringValueAttribute(string value) { 
     this.StringValue = value; 
    } 

    #endregion 

} 

public static class MyExtension 
{ 
    public static string GetStringValue(this Enum value) 
    { 
     // Get the type 
     Type type = value.GetType(); 

     // Get fieldinfo for this type 
     FieldInfo fieldInfo = type.GetField(value.ToString()); 

     // Get the stringvalue attributes 
     StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
      typeof(StringValueAttribute), false) as StringValueAttribute[]; 

     // Return the first if there was a match. 
     return attribs.Length > 0 ? attribs[0].StringValue : null; 
    } 

    public static String[] GetEnumNames(Type t) 
    { 
     Array enumValueArray= Enum.GetValues(t); 

     string[] enumStrings = new String[enumValueArray.Length]; 
     for(int i = 0; i< enumValueArray.Length; ++i) 
     { 
      enumStrings[i] = GetStringValue((test)enumValueArray.GetValue(i)); 
     } 

     return enumStrings; 
    } 
} 

enum test 
{ 
    [StringValue("test ONE")] 
    test1, 
    [StringValue("test TWO")] 
    test2 
} 
1

To również wydaje się działać:

[AttributeUsage(AttributeTargets.Field)] 
public class EnumDisplayNameAttribute : System.ComponentModel.DisplayNameAttribute 
{ 
    public EnumDisplayNameAttribute(string data) : base(data) { } 
} 

public enum Resolution_ : byte 
{ 
    DCIF, 
    CIF, 
    QCIF, 
    [EnumDisplayName("4CIF")] 
    CIF4, 
    [EnumDisplayName("2CIF")] 
    CIF2 
} 

Komponenty szuka atrybutu DisplayName poprzez odbicie znajdzie jeden, i tak daleko, jak tylko mogę powiedz, że to działa. Czy istnieje powód, dla którego może to być zły pomysł?

+0

Podoba mi się prostota tego pomysłu, ale niestety to nie zadziałało (tworzę strony opcji Visual Studio, ale nie wanny PropertyGrids). – Cameron

Powiązane problemy