在运行时隐藏PropertyGrid中的某些属性

7

我正在做一个项目,可以让用户自定义控件的属性。我有一个表单,其中包含LabelTextBoxButtonPropertyGrid控件。当用户点击Label时,我会在PropertyGrid中显示Label的属性,以下是使用的代码:

propertyGrid1.SelectedObject = SelectedControl;

但是我只想展示诸如BackColorFontForeColorText等属性。是否有可能隐藏这些属性,因为我不希望用户更改或显示它们?如果可以,该怎么做呢?

2个回答

8

我相信你正在寻找自定义类型描述符。

虽然其他答案分享了关于PropertyGridBrowsable属性和BrowsableAttributes的正确信息,但我认为这不是解决问题的适当实际方法。

对于现有的控件类(如LabelButton等),设置Browsable属性或任何其他自定义属性都不切实际。因为这样,操作者需要覆盖这些类的所有属性,并用适当的属性对其进行装饰。更糟糕的是,并非所有属性都可重写。

什么是切实可行的解决方案?

正如我之前提到的,我认为你正在寻找自定义类型描述符。您可以提供有关对象的元数据,分配新的TypeDescriptor或实现ICustomTypeDescriptor或从CustomTypeDescriptor派生。

示例

例如,在此处,我创建了一个从CustomTypeDescriptor派生的CustomObjectWrapper类,该类在构造函数中接受一个对象。通过这种方式,我可以通过重写GetProperties来简单地过滤包装对象的属性。

然后,我将其包装在CustomObjectWrapper中,而不是将button1分配给PropertyGrid。通过这种方式,它只显示过滤后的属性,而这些属性实际上来自于button1

以下是实现:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public class CustomObjectWrapper : CustomTypeDescriptor
{
    public object WrappedObject { get; private set; }
    public List<string> BrowsableProperties { get; private set; }
    public CustomObjectWrapper(object o)
        :base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o))
    {
        WrappedObject = o;
        BrowsableProperties = new List<string>() { "Text", "BackColor" };
    }
    public override PropertyDescriptorCollection GetProperties()
    {
        return this.GetProperties(new Attribute[] { });
    }
    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
                             .Where(p=>BrowsableProperties.Contains(p.Name))
                             .Select(p => TypeDescriptor.CreateProperty(
                                 WrappedObject.GetType(),
                                 p,
                                 p.Attributes.Cast<Attribute>().ToArray()))
                             .ToArray();
        return new PropertyDescriptorCollection(properties);
    }
}

并且用法:

propertyGrid1.SelectedObject = new CustomObjectWrapper(button1);

您可以将新的属性名称简单地添加到CustomObjectWrapperBrowsableProperties中。这是一个公共属性。

1
你认为继承ControlDesigner并重写其PreFilterProperties方法的设计师类怎么样?properties参数是一个IDictionary<string, PropertyDescriptor>。可以使用properties.Remove("[PropertyName]")来删除属性。 - Jimi
我尝试了这个,它非常好用。非常感谢你。 - Zhyke
@Jimi 感谢您的反馈。如果要求是在设计时,我会使用 ControlDesigner,就像这篇文章这篇文章中所示。但是在这里,OP要求在运行时通过设置 propertyGrid1.SelectedObject 来实现。这就是为什么我使用了 TypeDescriptor - Reza Aghaei
当然可以。我更感兴趣的是你对这个问题(潜在问题,缺点等)的看法。顺便说一下,这些答案在搜索中没有出现,真是遗憾。 - Jimi

5

更新

请注意,以下内容只适用于隐藏属性(如果可以的话)。 Reza Aghaei 的答案实际上是正确的答案。

我将保留此处,因为当您想要简单地隐藏一个已访问属性时,这很适用。

原始文本

最简单的方法可能是使用

[Browsable(false)]

BrowsableAttribute 类

指定属性或事件是否应在“属性”窗口中显示。

[Browsable(false)]
public int SecretSquirrels
{
  get; set;
}

正如 Marc Gravell 指出的那样,还有一个属性可以使用:

PropertyGrid.BrowsableAttributes 属性

获取或设置与属性网格所附加到的对象相关联的可浏览属性。


1
稍微概括一下,有一个BrowsableAttributes属性可以用来提供自定义过滤器(或:同一对象的不同视图),但是:[Browsable(false)]很可能已经满足了OP的需求。 - Marc Gravell
谢谢。我需要创建一个自定义的PropertyGrid吗?比如说,我想显示这个列表string[] ShowThisPropertyList = new string[] { "Text", "BackColor", "ForeColor" }; - Zhyke
@Zhyke 你可能需要创建一个新的对象,引用你想要的标签属性,并将其放入 propertyGrid。 - TheGeneral
虽然这个回答分享了有关PropertyGridBrowsable属性和BrowsableAttributes的正确信息,但我认为它不是解决问题的适当实际方案。为现有控件类(如LabelButton等)设置Browsable属性或任何其他自定义属性是不切实际的。因为这样一来,操作员需要覆盖这些类的所有属性,并用适当的属性进行装饰。更糟糕的是,并非所有属性都可以被覆盖。 - Reza Aghaei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接