条件“可浏览”属性

时间:2011-01-14 11:20:25

标签: c# properties conditional browsable


有没有办法让“可浏览”属性有条件,所以应用它的属性有时会出现在属性页面中,有时候不会出现?
谢谢:))

6 个答案:

答案 0 :(得分:9)

我不确定这适用于您的情况,但您可以通过调用以下函数在运行时调整“可浏览”装饰。

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

答案 1 :(得分:7)

没有简单的方法。

您可以通过实现ICustomTypeDescriptor来解决这个问题。这是一篇关于implementing ICustomTypeDescriptor的好文章。

或者您可以将自己的ControlDesigner与您的班级相关联,并覆盖PreFilterProperties方法,以添加或移除在媒体资源网格中查看的属性。

Removing certain properties from property grid.

答案 2 :(得分:6)

您可以通过提供自定义类型模型来实现此目的;在最简单的级别,您可以为从TypeDescriptor派生的类型提供自定义ExpandableObjectConverter,只需在奇思妙想中包含/排除给定的属性 - 但这仅适用于{ {1}} - 由属性页面使用。更复杂的方法是使用PropertyGrid / ICustomTypeDescriptor - 这可以在TypeDescriptionProvider

之类的内容中使用

答案 3 :(得分:1)

作为@ neoikon上面答案的改进,为了避免Ganesh在评论中提到的异常,这里有一个使用泛型来获取类型的版本:

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

然后,您还可以添加一个带有实例的版本:

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

用法:

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

答案 4 :(得分:0)

我遇到了这种方法,寻找一种方法来声明某些成员在IntelliSense中可见或隐藏,并且能够在编译时为所有需要隐藏的内容更改一次。我不知道这是不是你在找什么,但我找到了一个问题的答案......认为分享不会有什么坏处。

我设置了一个条件编译符号(在项目属性的Build选项卡中找到)IS_VIS(如果你想要显示某些成员,则值为true,如果你想隐藏它们则为false)然后:

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

然后在属性中引用isVis变量:

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

我在VB中这样做了,这被匆忙转换为c#。如果某些内容无效,请告诉我。

答案 5 :(得分:0)

John Cummings的解决方案基本上对我有用,但是由于他引入了泛型(虽然很聪明),但存在以下两个问题:

1-当将集合作为参数obj传递时,版本SetBrowsableProperty<T>(T obj, string strPropertyName, bool bIsBrowsable)将失败,因为在这种情况下,T将是IEnumerable的实现(例如List,Array等),而不是类型。真正想要的收藏。

2-它也允许传入基本类型,在这种情况下这毫无意义,并且几乎总是失败。

完成修订的解决方案:

因此,这是解决这些问题并为我工作的经过修订的解决方案: (我将方法和变量重命名了)

首先执行更改Browsable属性值的主要工作的实际方法:

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

现在,约翰·卡明斯(John Cummings)的解决方案中提出了<T>的变体:

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

现在有问题的过载没有。 1,但下面的修改现在可以处理:

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

这是实用程序函数,用于获取所有C#系统内置(原始)类型:

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

用法:

 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
}