2011-09-14 9 views
12

Ho una griglia di proprietà che sto utilizzando per consentire agli utenti di configurare gli oggetti per qualsiasi plug-in che è stato scritto per essere utilizzato nella mia applicazione. Mi piacerebbe essere in grado di dire agli sviluppatori che scrivono i plugin di utilizzare la ComponentModel attributi per i loro membri in questo modo:Modificare il nome visualizzato dei membri di enumerazione in un PropertyGrid

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

Questa grande opera. Ora vorrei che anche i membri di un'enumerazione potessero essere modificati. vale a dire

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

in modo che vengano visualizzati nella lista del PropertyGrid in questo modo:

DCIF 
CIF 
QCIF 
CIF4 
CIF2 

Insieme con le descrizioni e nomi di visualizzazione che possono avere con loro.

Sembra che posso farlo solo con proprietà, eventi e metodi. Qualcuno sa come posso fare questo per un'enumerazione?

risposta

14

Dovrai creare una classe EnumConverter e decorare la tua proprietà con un attributo TypeConverter per fare ciò.

Vai a questa Using PropertyGrid in .NET, è un esempio divertente:

Immaginate che si desidera più di due elementi nella lista. Il tipo booleano non è abbastanza; è necessario impostare gli attributi Description con un nome per ogni elemento in 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 
} 

In un'altra classe è necessario utilizzare il tipo di 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); 
    } 
} 

In terzo luogo, è necessario impostare l'attributo TypeConverter per la visualizzazione della proprietà.

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

Grazie! era così. Non so perché, ma un'ora con Google e ancora non ho trovato quell'articolo. –

+0

Bello, non ho mai incontrato EnumConverter nelle mie battaglie con PropertyGrid. –

+0

Collegamento ipertestuale "Using PropertyGrid in .NET" non è corretto ora. –

3

È possibile allegare un'implementazione personalizzata TypeConverter alla proprietà il cui tipo è il tuo enumerazione e ignorare il GetStandardValuesSupported e GetStandardValues per restituire un elenco personalizzato di elementi da visualizzare nella lista a discesa in PropertyGrid. È quindi possibile sovrascrivere i metodi ConvertFrom/ConvertTo per gestire i valori di conversione da/verso il tipo di enumerazione.

È anche possibile eseguire l'override di GetStandardValuesExclusive e restituirlo "true" in modo che l'utente non possa digitare nulla nel valore della proprietà.

Quindi, qualcosa di simile:

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

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

Nell'implementazione di GetStandardValues ​​/ ConvertFrom/ConvertTo si potrebbe quindi utilizzare la reflection per estrarre il DisplayNameAttribute (o DescriptionAttribute, che può essere più adatto a questo compito) attributi dei vari membri di enum per mostrare che il testo invece di codificare l'elenco degli elementi da mostrare.

4

La risposta che ho dato here ha un esempio funzionante di questo.Ecco il codice specifico da questo esempio che si desidera:

/// <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

Questo sembra anche funzionare:

[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 
} 

componenti alla ricerca di un attributo DisplayName tramite Reflection troveranno uno, e per quanto mi è possibile dì a questo funziona. C'è una ragione per cui questa potrebbe essere una cattiva idea?

+0

Mi piace la semplicità di questa idea, ma sfortunatamente non ha funzionato per me (sto creando pagine di opzioni di Visual Studio, però, non vanilla PropertyGrids). – Cameron

Problemi correlati