Atributo condicional “navegable”
-
11-10-2019 - |
Pregunta
¿Hay una manera de hacer una "navegable" condicional atributo, por lo que la propiedad que lo aplica a veces aparecen en la página de propiedades y, a veces, no?
Gracias:)
Solución
No hay manera fácil.
posiblemente puede resolver esto mediante la implementación de ICustomTypeDescriptor. Aquí es un buen artículo sobre implementar ICustomTypeDescriptor .
O se puede asociar su propio ControlDesigner con su clase y anular la PreFilterProperties método para añadir o propiedades quitan ver en la cuadrícula de propiedades.
Extracción ciertas propiedades de cuadrícula de propiedades.
Otros consejos
No estoy seguro de que esto se aplica a su situación, pero se puede ajustar la decoración "navegable" en tiempo de ejecución llamando a la función a continuación.
/// <summary>
/// Set the Browsable property.
/// NOTE: Be sure to decorate the property with [Browsable(true)]
/// </summary>
/// <param name="PropertyName">Name of the variable</param>
/// <param name="bIsBrowsable">Browsable Value</param>
private void setBrowsableProperty(string strPropertyName, bool bIsBrowsable)
{
// Get the Descriptor's Properties
PropertyDescriptor theDescriptor = TypeDescriptor.GetProperties(this.GetType())[strPropertyName];
// Get the Descriptor's "Browsable" Attribute
BrowsableAttribute theDescriptorBrowsableAttribute = (BrowsableAttribute)theDescriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo isBrowsable = theDescriptorBrowsableAttribute.GetType().GetField("Browsable", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
// Set the Descriptor's "Browsable" Attribute
isBrowsable.SetValue(theDescriptorBrowsableAttribute, bIsBrowsable);
}
Se puede hacer esto proporcionando un tipo-modelo personalizado; en el más simple nivel, puede proporcionar una TypeDescriptor
personalizado para su tipo derivado de ExpandableObjectConverter
, y simplemente incluir / excluir la propiedad dada a su antojo - pero esto sólo funciona con PropertyGrid
- utilizado por la página de propiedades. Un enfoque más complejo es el uso de ICustomTypeDescriptor
/ TypeDescriptionProvider
- esto puede entonces el trabajo dentro de las cosas como DataGridView
Como una mejora en la respuesta de @ neoikon arriba y para evitar la excepción Ganesh menciona en los comentarios, aquí hay una versión que utiliza los genéricos para obtener el tipo:
/// <summary>
/// Set the Browsable property.
/// NOTE: Be sure to decorate the property with [Browsable(true)]
/// </summary>
/// <param name="PropertyName">Name of the variable</param>
/// <param name="bIsBrowsable">Browsable Value</param>
private void SetBrowsableProperty<T>(string strPropertyName, bool bIsBrowsable)
{
// Get the Descriptor's Properties
PropertyDescriptor theDescriptor = TypeDescriptor.GetProperties(typeof(T))[strPropertyName];
// Get the Descriptor's "Browsable" Attribute
BrowsableAttribute theDescriptorBrowsableAttribute = (BrowsableAttribute)theDescriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo isBrowsable = theDescriptorBrowsableAttribute.GetType().GetField("Browsable", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
// Set the Descriptor's "Browsable" Attribute
isBrowsable.SetValue(theDescriptorBrowsableAttribute, bIsBrowsable);
}
A continuación, puede añadir también una versión que toma una instancia:
/// <summary>
/// Set the Browsable property.
/// NOTE: Be sure to decorate the property with [Browsable(true)]
/// </summary>
/// <param name="obj">An instance of the object whose property should be modified.</param>
/// <param name="PropertyName">Name of the variable</param>
/// <param name="bIsBrowsable">Browsable Value</param>
private void SetBrowsableProperty<T>(T obj, string strPropertyName, bool bIsBrowsable)
{
SetBrowsableProperty<T>(strPropertyName, bIsBrowsable);
}
Uso:
class Foo
{
[Browsable(false)]
public string Bar { get; set; }
}
void Example()
{
SetBrowsableProperty<Foo>("Bar", true);
Foo foo = new Foo();
SetBrowsableProperty(foo, "Bar", false);
}
Me encontré con este en busca de una forma de declarar ciertos miembros visible o escondido en IntelliSense y ser capaz de cambiar una vez por todas que necesitaba ser escondido en tiempo de compilación. No puedo decir si eso es lo que estabas buscando o no, pero me pareció una respuesta a mi pregunta ... pensé que no podría perjudicar a la acción.
un juego de símbolos de compilación condicional (que se encuentra en el separador Crear de propiedades del proyecto) IS_VIS (valor de ser cierto si desea que ciertos miembros para mostrar, falsa si su falta de ocultarlas) y luego:
#if IS_VIS
public const System.ComponentModel.EditorBrowsableState isVis =
ComponentModel.EditorBrowsableState.Always;
#else
public const System.ComponentModel.EditorBrowsableState isVis =
ComponentModel.EditorBrowsableState.Never;
#endif
A continuación referencia a la variable isVis en el atributo:
[EditorBrowsable(isVis)]
public string myMethod...
hice esto en VB y Este se convirtió a toda prisa a C #. Si algo no funciona bien, que me haga saber.
La solución de John Cummings básicamente trabajado para mí, pero tenía los siguientes dos problemas debido a su introducción de los genéricos (que era aunque muy inteligente):
1- la SetBrowsableProperty<T>(T obj, string strPropertyName, bool bIsBrowsable)
versión fallará cuando una colección se pasa como el obj parámetro porque T, en ese caso, será una implementación de IEnumerable (por ejemplo, Lista, Array etc.) y no el tipo de la colección que era en realidad previsto.
2- Permite que pasa en los tipos primitivos, así, que no tiene sentido en este caso y será casi siempre fallará.
solución revisada completa:
Así que aquí está la solución revisada que aborda estos problemas y ha trabajado para mí: (He cambiado el nombre ligeramente los métodos y las variables)
En primer lugar, el método real que hace el trabajo principal de cambiar el valor del atributo navegable:
/// <summary>
/// Sets the Browsable attribute value of a property of a non premitive type.
/// NOTE: The class property must be decorated with [Browsable(...)] attribute.
/// </summary>
/// <param name="type">The type that contains the property, of which the Browsable attribute value needs to be changed</param>
/// <param name="propertyName">Name of the type property, of which the Browsable attribute value needs to be changed</param>
/// <param name="isBrowsable">The new Browsable value</param>
public static void SetBrowsableAttributeOfAProperty(Type type, string propertyName, bool isBrowsable)
{
//Validate type - disallow primitive types (this will eliminate problem-2 as mentioned above)
if (type.IsEnum || BuiltInTypes.Contains(type))
throw new Exception($"The type '{type.Name}' is not supported");
var objPropertyInfo = TypeDescriptor.GetProperties(type);
// Get the Descriptor's Properties
PropertyDescriptor theDescriptor = objPropertyInfo[propertyName];
if (theDescriptor == null)
throw new Exception($"The property '{propertyName}' is not found in the Type '{type}'");
// Get the Descriptor's "Browsable" Attribute
BrowsableAttribute theDescriptorBrowsableAttribute = (BrowsableAttribute)theDescriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo browsablility = theDescriptorBrowsableAttribute.GetType().GetField("Browsable", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
// Set the Descriptor's "Browsable" Attribute
browsablility.SetValue(theDescriptorBrowsableAttribute, isBrowsable);
}
Ahora, la variante propuesta en solución de John Cummings con <T>
:
public static void SetBrowsableAttributeOfAProperty<T>(string propertyName, bool isBrowsable)
{
SetBrowsableAttributeOfAProperty(typeof(T), propertyName, isBrowsable);
}
Ahora, la sobrecarga que tenía el problema no. 1, pero la siguiente modificación mangos ahora:
/// <summary>
/// Sets the Browsable attribute value of a property of a non premitive type.
/// NOTE: The class property must be decorated with [Browsable(...)] attribute.
/// </summary>
/// <param name="obj">An instance of the type that contains the property, of which the Browsable attribute value needs to be changed.</param>
/// <param name="propertyName">Name of the type property, of which the Browsable attribute value needs to be changed</param>
/// <param name="isBrowsable">Browsable Value</param>
public static void SetBrowsableAttributeOfAProperty<T>(T obj, string propertyName, bool isBrowsable)
{
if (typeof(T).GetInterface("IEnumerable") != null && typeof(T) != typeof(string)) //String type needs to be filtered out as String also implements IEnumerable<char> but its not a normal collection rather a primitive type
{
//Get the element type of the IEnumerable collection
Type objType = obj.GetType().GetGenericArguments()?.FirstOrDefault(); //when T is a collection that implements IEnumerable except Array
if (objType == null) objType = obj.GetType().GetElementType(); //when T is an Array
SetBrowsableAttributeOfAProperty(objType, propertyName, isBrowsable);
}
else
SetBrowsableAttributeOfAProperty(typeof(T), propertyName, isBrowsable);
y aquí es función de utilidad para obtener todos los sistemas de C # tipos integrados (primitivas):
public static List<Type> BuiltInTypes
{
get
{
if (builtInTypes == null)
builtInTypes = Enum.GetValues(typeof(TypeCode)).Cast<TypeCode>().Select(t => Type.GetType("System." + Enum.GetName(typeof(TypeCode), t)))
.ToList();
return builtInTypes;
}
}
Uso:
class Foo
{
[Browsable(false)]
public string Bar { get; set; }
}
void Example()
{
SetBrowsableAttributeOfAProperty<Foo>("Bar", true); //works
Foo foo = new Foo();
SetBrowsableAttributeOfAProperty(foo, "Bar", false); //works
List<Foo> foos = new List<Foo> { foo, new Foo { Bar = "item2" } };
SetBrowsableAttributeOfAProperty(foos, "Bar", true); //works now, whereas it would crash with an exception in John Cummings's solution
}