67 votes

Changer le paramètre de l'attribut à l'exécution

Je ne suis pas sûr de savoir si c'est possible de changer l'attribut de paramètre au cours de l'exécution? Par exemple, à l'intérieur d'une assemblée j'ai la classe suivante

public class UserInfo
{
    [Category("change me!")]
    public int Age
    {
        get;
        set;
    }
    [Category("change me!")]
    public string Name
    {
        get;
        set;
    }
}

C'est une classe qui est fourni par un fournisseur tiers et je ne peux pas modifier le code. Mais maintenant j'ai trouvé que les descriptions ne sont pas exacts, et je veux changer le "change me" nom de la catégorie à autre chose quand je le lier à une instance de la classe ci-dessus à une propriété de la grille.

Pouvez-vous me dire comment faire cela?

28voto

Glenn Slaven Points 15742

Bien que vous apprenez quelque chose de nouveau chaque jour, apparemment j'ai menti:

Ce n'est généralement pas compris, c'est qu' vous pouvez modifier l'attribut d'instance valeurs assez facilement au moment de l'exécution. La raison en est, de bien sûr, que les instances de la classes d'attributs qui sont créés sont parfaitement normal objets et peut être utilisée sans restriction. Par exemple, nous pouvons obtenir l'objet:

ASCII[] attrs1=(ASCII[])
    typeof(MyClass).GetCustomAttributes(typeof(ASCII), false);

...changez la valeur de sa variable publique et de montrer qu'il a changé:

attrs1[0].MyData="A New String";
MessageBox.Show(attrs1[0].MyData);

...et finalement de créer une autre instance et de montrer que sa valeur est inchangée:

ASCII[] attrs3=(ASCII[])
    typeof(MyClass).GetCustomAttributes(typeof(ASCII), false);
 MessageBox.Show(attrs3[0].MyData);

http://www.vsj.co.uk/articles/display.asp?id=713

7voto

Jules Points 1527

Au cas où quelqu'un d'autre emprunterait cette voie, la réponse est que vous pouvez le faire, avec réflexion, sauf que vous ne pouvez pas, car il y a un bug dans le framework. Voici comment vous le feriez:

     Dim prop As PropertyDescriptor = TypeDescriptor.GetProperties(GetType(UserInfo))("Age")
    Dim att As CategoryAttribute = DirectCast(prop.Attributes(GetType(CategoryAttribute)), CategoryAttribute)
    Dim cat As FieldInfo = att.GetType.GetField("categoryValue", BindingFlags.NonPublic Or BindingFlags.Instance)
    cat.SetValue(att, "A better description")
 

Tout va bien, sauf que l'attribut category est modifié pour toutes les propriétés, et pas seulement pour «Age».

3voto

Marc Gravell Points 482669

Vous pouvez assez facilement sous-classer la plupart des attributs communs pour fournir cette extensibilité:

 using System;
using System.ComponentModel;
using System.Windows.Forms;
class MyCategoryAttribute : CategoryAttribute {
    public MyCategoryAttribute(string categoryKey) : base(categoryKey) { }

    protected override string GetLocalizedString(string value) {
        return "Whad'ya know? " + value;
    }
}

class Person {
    [MyCategory("Personal"), DisplayName("Date of Birth")]
    public DateTime DateOfBirth { get; set; }
}

static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.Run(new Form { Controls = {
           new PropertyGrid { Dock = DockStyle.Fill,
               SelectedObject = new Person { DateOfBirth = DateTime.Today}
           }}});
    }
}
 

Il existe des options plus complexes qui impliquent l'écriture de PropertyDescriptor s personnalisés, exposés via TypeConverter , ICustomTypeDescriptor ou TypeDescriptionProvider - mais cela est généralement excessif.

1voto

David MacDermot Points 11

Étant donné que l'élément sélectionné par PropertyGrid est "Age":

 SetCategoryLabelViaReflection(MyPropertyGrid.SelectedGridItem.Parent,
    MyPropertyGrid.SelectedGridItem.Parent.Label, "New Category Label");
 

SetCategoryLabelViaReflection() est défini comme suit:

 private void SetCategoryLabelViaReflection(GridItem category,
                                           string oldCategoryName,
                                           string newCategoryName)
{
    try
    {
        Type t = category.GetType();
        FieldInfo f = t.GetField("name",
                                 BindingFlags.NonPublic | BindingFlags.Instance);
        if (f.GetValue(category).Equals(oldCategoryName))
        {
            f.SetValue(category, newCategoryName);
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Trace.Write("Failed Renaming Category: " + ex.ToString());
    }
}
 

En ce qui concerne la programmation de l’élément sélectionné, la catégorie parente à modifier; il existe un certain nombre de solutions simples. Google "Définir le focus sur une propriété PropertyGrid spécifique".

0voto

Glenn Slaven Points 15742

Je ne pense vraiment pas, à moins que des réflexions géniales ne réussissent. Les décorations de la propriété sont définies au moment de la compilation et, à ma connaissance, sont fixes

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X