Domanda


Esiste un modo per fare un "sfogliabile" attributo condizionale, quindi la proprietà che lo applica a volte apparirà nella pagina delle proprietà e qualche volta no?
grazie:)

È stato utile?

Soluzione

Non v'è alcun modo semplice.

Si può eventualmente lavorare questo fuori implementando ICustomTypeDescriptor. Ecco un buon articolo su attuazione ICustomTypeDescriptor .

In alternativa, è possibile associare il proprio ControlDesigner con la tua classe e ignorare il PreFilterProperties metodo per aggiungere o rimuovere le proprietà visualizzate nella griglia delle proprietà.

Rimozione alcuni oggetti di griglia delle proprietà.

Altri suggerimenti

Non sono sicuro che questo vale per la vostra situazione, ma è possibile regolare la decorazione "sfogliabile" in fase di esecuzione chiamando la funzione qui sotto.

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

È possibile farlo fornendo un tipo-modello personalizzato; al semplice di livello, è possibile fornire un TypeDescriptor personalizzato per il vostro tipo derivato da ExpandableObjectConverter, e semplicemente includere / escludere la proprietà data a piacimento - ma questo funziona solo con PropertyGrid - utilizzato dalla pagina delle proprietà. Un approccio più complesso è quello di utilizzare ICustomTypeDescriptor / TypeDescriptionProvider - Questo lavoro può poi dentro le cose come DataGridView

Come un miglioramento di @ neoikon risposta di cui sopra e per evitare l'eccezione Ganesh citato nei commenti, qui è una versione che utilizza farmaci generici per ottenere il 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);
    }

È quindi possibile anche aggiungere una versione che prende un'istanza:

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

Utilizzo:

    class Foo
    {
        [Browsable(false)]
        public string Bar { get; set; }
    }
    void Example()
    {
        SetBrowsableProperty<Foo>("Bar", true);
        Foo foo = new Foo();
        SetBrowsableProperty(foo, "Bar", false);
    }

mi sono imbattuto in questo alla ricerca di un modo per dichiarare alcuni membri visibile o nascosto in IntelliSense ed essere in grado di cambiare una volta per tutte che doveva essere nascosta in fase di compilazione. Non posso dire se è quello che stavi cercando o no, ma ho trovato una risposta alla mia domanda ... pensato che non poteva ferire alla quota.

Ho impostato un simbolo compilazione condizionale (che si trova nella scheda Costruisci della proprietà del progetto) IS_VIS (valore essendo vero se si desidera alcuni membri per mostrare, false se il tuo vuole nascondere loro) e poi:

#if IS_VIS
    public const System.ComponentModel.EditorBrowsableState isVis =
        ComponentModel.EditorBrowsableState.Always;
#else
    public const System.ComponentModel.EditorBrowsableState isVis =
        ComponentModel.EditorBrowsableState.Never;
#endif

È quindi riferimento alla variabile isVis nell'attributo:

[EditorBrowsable(isVis)]
public string myMethod...

Ho fatto questo in VB e questo è stato frettolosamente convertito in c #. Se qualcosa non funziona bene, me lo faccia sapere.

La soluzione di John Cummings fondamentalmente lavorato per me, ma aveva i seguenti due problemi a causa della sua introduzione della Generics (che era abbastanza intelligente però):

1- la versione SetBrowsableProperty<T>(T obj, string strPropertyName, bool bIsBrowsable) fallirà quando una collezione viene passato come parametro obj causa T, in tal caso, sarà un'implementazione di IEnumerable (es List, Array etc.) e non il tipo di raccolta che era effettivamente destinato.

2- Permette passando tipi primitivi pure, che è inutile in questo caso e sarà quasi sempre sicuro.

Soluzione completa revisione:

Quindi, ecco la soluzione rivista che affronta questi problemi e ha funzionato per me: (Ho un po 'rinominato i metodi e le variabili)

In primo luogo il metodo effettivo che fa il lavoro principale di cambiare il valore di attributo sfogliabile:

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

Ora la variante proposta in soluzione di John Cummings con <T>:

public static void SetBrowsableAttributeOfAProperty<T>(string propertyName, bool isBrowsable)
{
    SetBrowsableAttributeOfAProperty(typeof(T), propertyName, isBrowsable);
}

Ora il sovraccarico che ha avuto il problema n. 1, ma la seguente modifica maniglie subito:

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

e qui è la funzione di utilità per ottenere tutti i sistema di C # tipi built-in (primitivi):

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

Utilizzo:

 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
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top