2

尝试通过更改 Browsable 属性来删除或放置属性网格上的项目。

但是除非在对象创建时设置了可浏览,否则我更改可浏览的代码不起作用。现在我可以手动添加可浏览的,但是当我对我的实体进行更改(仍在开发项目,对实体进行大量更改)时,我添加的任何其他属性都会消失。

我试图以其他方式设置 [Browsable(true)] 两种方式:http ://ardalis.com/adding-attributes-to-generated-classes和http://social.msdn.microsoft.com/Forums/en-US /adodotnetentityframework/thread/617ebfca-0f68-4b90-83fd-0da758fadbd0/

两者似乎实际上都正确设置了 Browsable,但是当我通过 Property Descriptor 中的 Attributes 循环时,它不存在(让我更改)。

  String fieldname = "browsable"; // I also edit "description"
  PropertyDescriptor pd = TypeDescriptor.GetProperties(o.GetType())[propertyName];
  object attrib = null;
  AttributeCollection attribs = pd.Attributes;

  foreach (Attribute a in attribs)
    {
    if (a.GetType() == attributeType)
      {
      attrib = a;
      break;
      }
    }
// The microsoft documentation leads one to believe the following line of code would find the desired attribute,
// negating the need for the more complete foreach statement above.
// However,  it appears to find attribute even when it does not exist. Setting value for "found" attribute 
// will result in random memory being changed, which results in very unpredictable behavior.
// attrib = pd.Attributes[t];

if (attrib != null)
  {
  // locate field that contains value 
  FieldInfo field = attrib.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
  if (field != null)
    {
    if (field.FieldType == value.GetType())
      {
      // set field to desired value
      field.SetValue(attrib, value);
      }
    }
    }
  else
    {
    throw new Exception("Attribute (" + attributeType.Name + ") does not exist for Property(" + propertyName + ")");
    }

因此,如果找不到“可浏览”,我会不断收到我抛出的异常-但前提是未首先在 Model.Designer.cs 中设置。

下面是我的 Model.Designer.cs 的样子。

  /// <summary>
  /// No Metadata Documentation available.
  /// </summary>
  [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
  [DataMemberAttribute()]
  [Browsable(false)] // this works, but goes away if change my entity
  public Nullable<global::System.TimeSpan> SignoutAfter
    {
    get
      {
      return _SignoutAfter;
      }
    set
      {
      OnSignoutAfterChanging(value);
      ReportPropertyChanging("SignoutAfter");
      _SignoutAfter = StructuralObject.SetValidValue(value);
      ReportPropertyChanged("SignoutAfter");
      OnSignoutAfterChanged();
      }
    }
  private Nullable<global::System.TimeSpan> _SignoutAfter;
  partial void OnSignoutAfterChanging(Nullable<global::System.TimeSpan> value);
  partial void OnSignoutAfterChanged();

所以我需要一种方法来 1. 在我编辑实体时添加可浏览实体,因此它可能总是在编辑 t4,但我什至不知道从哪里开始,或者 2. 添加或删除的另一种方法(和编辑)属性(请参阅我可能会根据某些逻辑编辑描述)或 3 在我的代码中找到漏洞,以便我可以找到并编辑可浏览的(描述和显示名称)。

更新上面的第二个链接http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/617ebfca-0f68-4b90-83fd-0da758fadbd0/有很多我需要的东西,我想。向类中添加 Attribute 数组变量和一些代码以查看是否已设置似乎具有我正在寻找的效果。但是让这个开放以找到更好的答案。

partial class Client : ICustomTypeDescriptor
  {
   public Attribute[] SignOutAttributes; // added this

   #region ICustomTypeDescriptor Members

   ... // see the link for the other code

   public PropertyDescriptorCollection GetProperties (Attribute[] attributes)
      {
      var propsColl = TypeDescriptor.GetProperties (this, attributes, true);
      var props = new List<PropertyDescriptor> ();
      foreach (PropertyDescriptor prop in propsColl)
         {
         String strUPPERCaseName = prop.Name.ToUpper (); // for my thick fingers
         // make sure case values are upper case 
         switch (strUPPERCaseName)
            {
            case "SIGNOUTAFTER":
               if (SignOutAttributes != null)
                  {
                  props.Add(new CustomPropertyDescriptor(prop, SignOutAttributes));
                  }
                else
                  {
                   props.Add (new CustomPropertyDescriptor (prop, new Attribute[]
                     {
                     new CategoryAttribute("Settings"),
                     new DisplayNameAttribute("Signout After"),
                     new BrowsableAttribute(true),
                     new ReadOnlyAttribute(false)
                     }));
                  }
                break;
            default:
               props.Add (prop);
               break;
            }
         }
       return new PropertyDescriptorCollection (props.ToArray ());
       }

在我的代码中,我可以更改属性数组以获得我想要的属性值。

 _client.SignOutAttributes = new Attribute[]
                {
                    new CategoryAttribute ("My Category"),
                    new DisplayNameAttribute("Signout After"),
                    new BrowsableAttribute(true),
                    new ReadOnlyAttribute(false)
                };

我对此不是 100% 满意。我必须为每个属性编写代码。

4

1 回答 1

11

当您需要动态(在运行时设置)属性时,使用ICustomTypeDescriptor绝对是一个很好的解决方案。这是我一直用于这种属性网格黑客的通用 ICustomTypeDescriptor 实用程序类,使用起来非常简单:

public sealed class DynamicTypeDescriptor: ICustomTypeDescriptor, INotifyPropertyChanged
{
    private Type _type;
    private AttributeCollection _attributes;
    private TypeConverter _typeConverter;
    private Dictionary<Type, object> _editors;
    private EventDescriptor _defaultEvent;
    private PropertyDescriptor _defaultProperty;
    private EventDescriptorCollection _events;

    public event PropertyChangedEventHandler PropertyChanged;

    private DynamicTypeDescriptor()
    {
    }

    public DynamicTypeDescriptor(Type type)
    {
        if (type == null)
            throw new ArgumentNullException("type");

        _type = type;
        _typeConverter = TypeDescriptor.GetConverter(type);
        _defaultEvent = TypeDescriptor.GetDefaultEvent(type);
        _defaultProperty = TypeDescriptor.GetDefaultProperty(type);
        _events = TypeDescriptor.GetEvents(type);

        List<PropertyDescriptor> normalProperties = new List<PropertyDescriptor>();
        OriginalProperties = TypeDescriptor.GetProperties(type);
        foreach (PropertyDescriptor property in OriginalProperties)
        {
            if (!property.IsBrowsable)
                continue;

            normalProperties.Add(property);

        }
        Properties = new PropertyDescriptorCollection(normalProperties.ToArray());

        _attributes = TypeDescriptor.GetAttributes(type);

        _editors = new Dictionary<Type, object>();
        object editor = TypeDescriptor.GetEditor(type, typeof(UITypeEditor));
        if (editor != null)
        {
            _editors.Add(typeof(UITypeEditor), editor);
        }
        editor = TypeDescriptor.GetEditor(type, typeof(ComponentEditor));
        if (editor != null)
        {
            _editors.Add(typeof(ComponentEditor), editor);
        }
        editor = TypeDescriptor.GetEditor(type, typeof(InstanceCreationEditor));
        if (editor != null)
        {
            _editors.Add(typeof(InstanceCreationEditor), editor);
        }
    }

    public T GetPropertyValue<T>(string name, T defaultValue)
    {
        if (name == null)
            throw new ArgumentNullException("name");

        foreach (PropertyDescriptor pd in Properties)
        {
            if (pd.Name == name)
            {
                try
                {
                    return (T)Convert.ChangeType(pd.GetValue(Component), typeof(T));
                }
                catch
                {
                    return defaultValue;
                }
            }
        }
        return defaultValue;
    }

    public void SetPropertyValue(string name, object value)
    {
        if (name == null)
            throw new ArgumentNullException("name");

        foreach (PropertyDescriptor pd in Properties)
        {
            if (pd.Name == name)
            {
                pd.SetValue(Component, value);
                break;
            }
        }
    }

    internal void OnValueChanged(PropertyDescriptor prop)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(prop.Name));
        }
    }

    internal static T GetAttribute<T>(AttributeCollection attributes) where T : Attribute
    {
        if (attributes == null)
            return null;

        foreach (Attribute att in attributes)
        {
            if (typeof(T).IsAssignableFrom(att.GetType()))
                return (T)att;
        }
        return null;
    }

    public sealed class DynamicProperty: PropertyDescriptor, INotifyPropertyChanged
    {
        private readonly Type _type;
        private readonly bool _hasDefaultValue;
        private readonly object _defaultValue;
        private readonly PropertyDescriptor _existing;
        private readonly DynamicTypeDescriptor _descriptor;
        private Dictionary<Type, object> _editors;
        private bool? _readOnly;
        private bool? _browsable;
        private string _displayName;
        private string _description;
        private string _category;
        private List<Attribute> _attributes = new List<Attribute>();

        public event PropertyChangedEventHandler PropertyChanged;

        internal DynamicProperty(DynamicTypeDescriptor descriptor, Type type, object value, string name, Attribute[] attrs)
            : base(name, attrs)
        {
            _descriptor = descriptor;
            _type = type;
            Value = value;
            DefaultValueAttribute def = DynamicTypeDescriptor.GetAttribute<DefaultValueAttribute>(Attributes);
            if (def == null)
            {
                _hasDefaultValue = false;
            }
            else
            {
                _hasDefaultValue = true;
                _defaultValue = def.Value;
            }
            if (attrs != null)
            {
                foreach (Attribute att in attrs)
                {
                    _attributes.Add(att);
                }
            }
        }

        internal static Attribute[] GetAttributes(PropertyDescriptor existing)
        {
            List<Attribute> atts = new List<Attribute>();
            foreach (Attribute a in existing.Attributes)
            {
                atts.Add(a);
            }
            return atts.ToArray();
        }

        internal DynamicProperty(DynamicTypeDescriptor descriptor, PropertyDescriptor existing, object component)
            : this(descriptor, existing.PropertyType, existing.GetValue(component), existing.Name, GetAttributes(existing))
        {
            _existing = existing;
        }

        public void RemoveAttributesOfType<T>() where T : Attribute
        {
            List<Attribute> remove = new List<Attribute>();
            foreach (Attribute att in _attributes)
            {
                if (typeof(T).IsAssignableFrom(att.GetType()))
                {
                    remove.Add(att);
                }
            }

            foreach (Attribute att in remove)
            {
                _attributes.Remove(att);
            }
        }

        public IList<Attribute> AttributesList
        {
            get
            {
                return _attributes;
            }
        }

        public override AttributeCollection Attributes
        {
            get
            {
                return new AttributeCollection(_attributes.ToArray());
            }
        }

        public object Value { get; set; }

        public override bool CanResetValue(object component)
        {
            if (_existing != null)
                return _existing.CanResetValue(component);

            return _hasDefaultValue;
        }

        public override Type ComponentType
        {
            get
            {
                if (_existing != null)
                    return _existing.ComponentType;

                return typeof(object);
            }
        }

        public override object GetValue(object component)
        {
            if (_existing != null)
                return _existing.GetValue(component);

            return Value;
        }

        public override string Category
        {
            get
            {
                if (_category != null)
                    return _category;

                return base.Category;
            }
        }

        public void SetCategory(string category)
        {
            _category = category;
        }

        public override string Description
        {
            get
            {
                if (_description != null)
                    return _description;

                return base.Description;
            }
        }

        public void SetDescription(string description)
        {
            _description = description;
        }

        public override string DisplayName
        {
            get
            {
                if (_displayName != null)
                    return _displayName;

                if (_existing != null)
                    return _existing.DisplayName;

                return base.DisplayName;
            }
        }

        public void SetDisplayName(string displayName)
        {
            _displayName = displayName;
        }

        public override bool IsBrowsable
        {
            get
            {
                if (_browsable.HasValue)
                    return _browsable.Value;

                return base.IsBrowsable;
            }
        }

        public void SetBrowsable(bool browsable)
        {
            _browsable = browsable;
        }

        public override bool IsReadOnly
        {
            get
            {
                if (_readOnly.HasValue)
                    return _readOnly.Value;

                if (_existing != null)
                    return _existing.IsReadOnly;

                ReadOnlyAttribute att = DynamicTypeDescriptor.GetAttribute<ReadOnlyAttribute>(Attributes);
                if (att == null)
                    return false;

                return att.IsReadOnly;
            }
        }

        public void SetIsReadOnly(bool readOnly)
        {
            _readOnly = readOnly;
        }

        public override Type PropertyType
        {
            get
            {
                if (_existing != null)
                    return _existing.PropertyType;

                return _type;
            }
        }

        public override void ResetValue(object component)
        {
            if (_existing != null)
            {
                _existing.ResetValue(component);
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(Name));
                }
                _descriptor.OnValueChanged(this);
                return;
            }

            if (CanResetValue(component))
            {
                Value = _defaultValue;
                _descriptor.OnValueChanged(this);
            }
        }

        public override void SetValue(object component, object value)
        {
            if (_existing != null)
            {
                _existing.SetValue(component, value);
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(Name));
                }
                _descriptor.OnValueChanged(this);
                return;
            }

            Value = value;
            _descriptor.OnValueChanged(this);
        }

        public override bool ShouldSerializeValue(object component)
        {
            if (_existing != null)
                return _existing.ShouldSerializeValue(component);

            return false;
        }

        public override object GetEditor(Type editorBaseType)
        {
            if (editorBaseType == null)
                throw new ArgumentNullException("editorBaseType");

            if (_editors != null)
            {
                object type;
                if ((_editors.TryGetValue(editorBaseType, out type)) && (type != null))
                    return type;
            }
            return base.GetEditor(editorBaseType);
        }

        public void SetEditor(Type editorBaseType, object obj)
        {
            if (editorBaseType == null)
                throw new ArgumentNullException("editorBaseType");

            if (_editors == null)
            {
                if (obj == null)
                    return;

                _editors = new Dictionary<Type, object>();
            }
            if (obj == null)
            {
                _editors.Remove(editorBaseType);
            }
            else
            {
                _editors[editorBaseType] = obj;
            }
        }
    }

    public PropertyDescriptor AddProperty(Type type, string name, object value, string displayName, string description, string category, bool hasDefaultValue, object defaultValue, bool readOnly)
    {
        return AddProperty(type, name, value, displayName, description, category, hasDefaultValue, defaultValue, readOnly, null);
    }

    public PropertyDescriptor AddProperty(
        Type type,
        string name,
        object value,
        string displayName,
        string description,
        string category,
        bool hasDefaultValue,
        object defaultValue,
        bool readOnly,
        Type uiTypeEditor)
    {
        if (type == null)
            throw new ArgumentNullException("type");

        if (name == null)
            throw new ArgumentNullException("name");

        List<Attribute> atts = new List<Attribute>();
        if (!string.IsNullOrEmpty(displayName))
        {
            atts.Add(new DisplayNameAttribute(displayName));
        }

        if (!string.IsNullOrEmpty(description))
        {
            atts.Add(new DescriptionAttribute(description));
        }

        if (!string.IsNullOrEmpty(category))
        {
            atts.Add(new CategoryAttribute(category));
        }

        if (hasDefaultValue)
        {
            atts.Add(new DefaultValueAttribute(defaultValue));
        }

        if (uiTypeEditor != null)
        {
            atts.Add(new EditorAttribute(uiTypeEditor, typeof(UITypeEditor)));
        }

        if (readOnly)
        {
            atts.Add(new ReadOnlyAttribute(true));
        }

        DynamicProperty property = new DynamicProperty(this, type, value, name, atts.ToArray());
        AddProperty(property);
        return property;
    }

    public void RemoveProperty(string name)
    {
        if (name == null)
            throw new ArgumentNullException("name");

        List<PropertyDescriptor> remove = new List<PropertyDescriptor>();
        foreach (PropertyDescriptor pd in Properties)
        {
            if (pd.Name == name)
            {
                remove.Add(pd);
            }
        }

        foreach (PropertyDescriptor pd in remove)
        {
            Properties.Remove(pd);
        }
    }

    public void AddProperty(PropertyDescriptor property)
    {
        if (property == null)
            throw new ArgumentNullException("property");

        Properties.Add(property);
    }

    public override string ToString()
    {
        return base.ToString() + " (" + Component + ")";
    }

    public PropertyDescriptorCollection OriginalProperties { get; private set; }
    public PropertyDescriptorCollection Properties { get; private set; }

    public DynamicTypeDescriptor FromComponent(object component)
    {
        if (component == null)
            throw new ArgumentNullException("component");

        if (!_type.IsAssignableFrom(component.GetType()))
            throw new ArgumentException(null, "component");

        DynamicTypeDescriptor desc = new DynamicTypeDescriptor();
        desc._type = _type;
        desc.Component = component;

        // shallow copy on purpose
        desc._typeConverter = _typeConverter;
        desc._editors = _editors;
        desc._defaultEvent = _defaultEvent;
        desc._defaultProperty = _defaultProperty;
        desc._attributes = _attributes;
        desc._events = _events;
        desc.OriginalProperties = OriginalProperties;

        // track values
        List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
        foreach (PropertyDescriptor pd in Properties)
        {
            DynamicProperty ap = new DynamicProperty(desc, pd, component);
            properties.Add(ap);
        }

        desc.Properties = new PropertyDescriptorCollection(properties.ToArray());
        return desc;
    }

    public object Component { get; private set; }
    public string ClassName { get; set; }
    public string ComponentName { get; set; }

    AttributeCollection ICustomTypeDescriptor.GetAttributes()
    {
        return _attributes;
    }

    string ICustomTypeDescriptor.GetClassName()
    {
        if (ClassName != null)
            return ClassName;

        if (Component != null)
            return Component.GetType().Name;

        if (_type != null)
            return _type.Name;

        return null;
    }

    string ICustomTypeDescriptor.GetComponentName()
    {
        if (ComponentName != null)
            return ComponentName;

        return Component != null ? Component.ToString() : null;
    }

    TypeConverter ICustomTypeDescriptor.GetConverter()
    {
        return _typeConverter;
    }

    EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
    {
        return _defaultEvent;
    }

    PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
    {
        return _defaultProperty;
    }

    object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
    {
        object editor;
        if (_editors.TryGetValue(editorBaseType, out editor))
            return editor;

        return null;
    }

    EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
    {
        return _events;
    }

    EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
    {
        return _events;
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
    {
        return Properties;
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        return Properties;
    }

    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
    {
        return Component;
    }
}
于 2013-05-09T06:11:55.227 回答