64 votos

Cambiar el Atributo del parámetro en tiempo de ejecución

No estoy seguro de si es posible el cambio de parámetro del atributo durante el tiempo de ejecución? Por ejemplo, dentro de una asamblea que tengo la siguiente clase

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

Esta es una clase que es proporcionado por un proveedor de terceros y no puedo cambiar el código. Pero ahora he encontrado que las anteriores descripciones no son exactos, y quiero cambiar el "change me" nombre de la categoría a otra cosa cuando me unen una instancia de la clase anterior a una cuadrícula de propiedades.

Puedo saber cómo hacer esto?

27voto

Glenn Slaven Puntos 15742

Bien aprender algo nuevo cada día, al parecer me mintió:

Lo general, no se dio cuenta es que usted puede cambiar el atributo de instancia valores bastante fácilmente en tiempo de ejecución. La razón es, de supuesto, de que las instancias de la clases de atributos que se crean son perfectamente normal objetos y puede ser utilizado sin restricciones. Por ejemplo, podemos obtener el objeto:

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

...cambiar el valor de su variable pública y demostrar que ha cambiado:

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

...y, finalmente, crear otra instancia y muestran que su valor no se modifica:

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 Puntos 1527

En caso de que alguien camina abajo de esta avenida, la respuesta es que usted puede hacerlo, con la reflexión, excepto que no puede porque hay un bug en el marco. Aquí está cómo hacerlo:

    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")

Todo muy bien, excepto que el atributo de la categoría es cambiado para todas las propiedades, no sólo la "Edad".

3voto

Marc Gravell Puntos 482669

Usted puede subclase de la mayoría de los atributos comunes muy fácilmente para proporcionar esta extensibilidad:

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}
           }}});
    }
}

Hay opciones más complejas que implican la escritura personalizada PropertyDescriptors, expuestos a través de TypeConverter, ICustomTypeDescriptor o TypeDescriptionProvider - pero que suele ser una exageración.

1voto

David MacDermot Puntos 11

Dado que el PropertyGrid del elemento seleccionado es "Edad":

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

Donde SetCategoryLabelViaReflection() se define como sigue:

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());
    }
}

Tan lejos como a través de programación ajuste el elemento seleccionado, la principal categoría de la que desea cambiar; hay un número de soluciones simples. Google "Establecer el Foco en un determinado PropertyGrid de la propiedad".

0voto

Glenn Slaven Puntos 15742

Yo realmente no lo creo, a menos que haya alguna funky reflexión que puede sacar adelante. La propiedad decoraciones se establece en tiempo de compilación y mis conocimientos son fijos

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X