繁体   English   中英

如何在运行时更改DisplayNameAttribute以在Property Grid C#中使用

[英]How to change the DisplayNameAttribute on runtime to use in a Property Grid C#

我想知道如何在运行时更改DisplayNameAttribute,当我进行一些转换时,我希望displayName在我的属性网格中是Feet而不是Meters,这可能吗?

[DisplayName("Meters")]
public double Distance
  {
     get{return distance;}
  }

有许多不同的方法可以做到这一点。 最简单的是做一些类似于某些i18n产品的做法 - 将属性子类化并截取文本; 但这仅在您拥有该类型时才有效,并且您无法访问该上下文。

接下来要看的是TypeConverter ,因为它提供了对属性的组件模型视图的访问,并且比接下来的两个选项更简单;-p这将适用于PropertyGrid ,但不适用于DataGridView等。

列表中的下一个是ICustomTypeDescriptor - 不是一个有趣的实现接口,但您可以交换自己的属性描述符。 这要求您拥有该类型(以提供接口支持)。

最后, CustomTypeDescriptor就像是最后一个,但它甚至适用于您不拥有的类型,并允许在类型对象级别访问调整的元数据(其他一切只支持对象 )。

选择哪个? 我怀疑TypeConverter是最明智的; 你需要对象上下文(子类属性不提供),但你不需要额外的复杂性。

这是一个例子; 请注意,在TypeConverter代码中,我们可以访问对象上下文。 如果名称很简单,那么将它放入TypeConverter (创建属性时)就足够了。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
class MyFunkyTypeConverter : ExpandableObjectConverter
{
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        PropertyDescriptorCollection props = base.GetProperties(context, value, attributes);
        List<PropertyDescriptor> list = new List<PropertyDescriptor>(props.Count);
        foreach (PropertyDescriptor prop in props)
        {
            switch (prop.Name)
            {
                case "Distance":
                    list.Add(new DisplayNamePropertyDescriptor(
                        prop, "your magic code here"));
                    break;
                default:
                    list.Add(prop);
                    break;
            }
        }
        return new PropertyDescriptorCollection(list.ToArray(), true);
    }
}
class DisplayNamePropertyDescriptor : PropertyDescriptor
{
    private readonly string displayName;
    private readonly PropertyDescriptor parent;
    public DisplayNamePropertyDescriptor(
        PropertyDescriptor parent, string displayName) : base(parent)
    {
        this.displayName = displayName;
        this.parent = parent;
    }
    public override string  DisplayName
    {get { return displayName; } }

    public override bool ShouldSerializeValue(object component)
    { return parent.ShouldSerializeValue(component); }

    public override void SetValue(object component, object value) {
        parent.SetValue(component, value);
    }
    public override object GetValue(object component)
    {
        return parent.GetValue(component);
    }
    public override void ResetValue(object component)
    {
        parent.ResetValue(component);
    }
    public override bool CanResetValue(object component)
    {
        return parent.CanResetValue(component);
    }
    public override bool IsReadOnly
    {
        get { return parent.IsReadOnly; }
    }
    public override void AddValueChanged(object component, EventHandler handler)
    {
        parent.AddValueChanged(component, handler);
    }
    public override void RemoveValueChanged(object component, EventHandler handler)
    {
        parent.RemoveValueChanged(component, handler);
    }
    public override bool SupportsChangeEvents
    {
        get { return parent.SupportsChangeEvents; }
    }
    public override Type PropertyType
    {
        get { return parent.PropertyType; }
    }
    public override TypeConverter Converter
    {
        get { return parent.Converter; }
    }
    public override Type ComponentType
    {
        get { return parent.ComponentType; }
    }
    public override string Description
    {
        get { return parent.Description; }
    }
    public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
    {
        return parent.GetChildProperties(instance, filter);
    }
    public override string Name
    {
        get { return parent.Name; }
    }

}

[TypeConverter(typeof(MyFunkyTypeConverter))]
class MyFunkyType
{
    public double Distance {get;set;}

    public double AnotherProperty { get; set; }
}
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new Form { Controls = {
            new PropertyGrid { Dock = DockStyle.Fill,
                SelectedObject = new MyFunkyType {
                    Distance = 123.45
                }}
        }});
    }
}

属性被编译为类型的一部分,因此无法在运行时更改它们。

另一种解决方案可以是确定您始终存储所有值的内部计量单位。 米是一个很好的候选人。 然后创建位于您的使用者类和原始类之间的“翻译器”服务,该类负责将所有值转换为不同的格式。

在显示名称中设置单位有点奇怪,但如果这确实是您想要做的,那么您唯一的解决方案是使用自定义PropertyDescriptors发布您的属性(感谢TypeConverter或自定义类型描述符)并且覆盖DisplayName属性。

这里也回答: 更改属性的DisplayName属性

我不知道这是否有效,但您的DisplayName是一个属性。 每个类和每个类的成员都可以设置属性。 也就是说,PropertyInfo会让您访问此属性。 现在,如果你走这条路并来到PropertyInfo.GetCustomAttributes()或类似的东西,并且你检索你的属性值,你说这是只读的,就像你对尼克说的那样吗?

如果displayname属性已存在(如此情况)并且您只想更改名称,则可以使用此属性的propertydescriptor。 只需查看属性属性,直到找到属性并更改值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM