www.pudn.com > PropertyBag.rar > PropertyBag.cs
/********************************************************************
*
* PropertyBag.cs
* --------------
* Copyright (C) 2002 Tony Allowatt
* Last Update: 12/14/2002
*
* THE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT WARRANTY
* OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE AUTHOR BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF THIS
* SOFTWARE.
*
* Public types defined in this file:
* ----------------------------------
* namespace Flobbster.Windows.Forms
* class PropertySpec
* class PropertySpecEventArgs
* delegate PropertySpecEventHandler
* class PropertyBag
* class PropertyBag.PropertySpecCollection
* class PropertyTable
*
********************************************************************/
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing.Design;
namespace Flobbster.Windows.Forms
{
///
/// Represents a single property in a PropertySpec.
///
public class PropertySpec
{
private Attribute[] attributes;
private string category;
private object defaultValue;
private string description;
private string editor;
private string name;
private string type;
private string typeConverter;
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
public PropertySpec(string name, string type) : this(name, type, null, null, null) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
public PropertySpec(string name, Type type) :
this(name, type.AssemblyQualifiedName, null, null, null) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
/// The category under which the property is displayed in the
/// property grid.
public PropertySpec(string name, string type, string category) : this(name, type, category, null, null) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
///
public PropertySpec(string name, Type type, string category) :
this(name, type.AssemblyQualifiedName, category, null, null) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
public PropertySpec(string name, string type, string category, string description) :
this(name, type, category, description, null) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
public PropertySpec(string name, Type type, string category, string description) :
this(name, type.AssemblyQualifiedName, category, description, null) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
public PropertySpec(string name, string type, string category, string description, object defaultValue)
{
this.name = name;
this.type = type;
this.category = category;
this.description = description;
this.defaultValue = defaultValue;
this.attributes = null;
}
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
public PropertySpec(string name, Type type, string category, string description, object defaultValue) :
this(name, type.AssemblyQualifiedName, category, description, defaultValue) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The fully qualified name of the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The fully qualified name of the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, string type, string category, string description, object defaultValue,
string editor, string typeConverter) : this(name, type, category, description, defaultValue)
{
this.editor = editor;
this.typeConverter = typeConverter;
}
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The fully qualified name of the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The fully qualified name of the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, Type type, string category, string description, object defaultValue,
string editor, string typeConverter) :
this(name, type.AssemblyQualifiedName, category, description, defaultValue, editor, typeConverter) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The Type that represents the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The fully qualified name of the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, string type, string category, string description, object defaultValue,
Type editor, string typeConverter) :
this(name, type, category, description, defaultValue, editor.AssemblyQualifiedName,
typeConverter) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The Type that represents the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The fully qualified name of the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, Type type, string category, string description, object defaultValue,
Type editor, string typeConverter) :
this(name, type.AssemblyQualifiedName, category, description, defaultValue,
editor.AssemblyQualifiedName, typeConverter) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The fully qualified name of the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The Type that represents the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, string type, string category, string description, object defaultValue,
string editor, Type typeConverter) :
this(name, type, category, description, defaultValue, editor, typeConverter.AssemblyQualifiedName) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The fully qualified name of the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The Type that represents the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, Type type, string category, string description, object defaultValue,
string editor, Type typeConverter) :
this(name, type.AssemblyQualifiedName, category, description, defaultValue, editor,
typeConverter.AssemblyQualifiedName) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// The fully qualified name of the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The Type that represents the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The Type that represents the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, string type, string category, string description, object defaultValue,
Type editor, Type typeConverter) :
this(name, type, category, description, defaultValue, editor.AssemblyQualifiedName,
typeConverter.AssemblyQualifiedName) { }
///
/// Initializes a new instance of the PropertySpec class.
///
/// The name of the property displayed in the property grid.
/// A Type that represents the type of the property.
/// The category under which the property is displayed in the
/// property grid.
/// A string that is displayed in the help area of the
/// property grid.
/// The default value of the property, or null if there is
/// no default value.
/// The Type that represents the type of the editor for this
/// property. This type must derive from UITypeEditor.
/// The Type that represents the type of the type
/// converter for this property. This type must derive from TypeConverter.
public PropertySpec(string name, Type type, string category, string description, object defaultValue,
Type editor, Type typeConverter) :
this(name, type.AssemblyQualifiedName, category, description, defaultValue,
editor.AssemblyQualifiedName, typeConverter.AssemblyQualifiedName) { }
///
/// Gets or sets a collection of additional Attributes for this property. This can
/// be used to specify attributes beyond those supported intrinsically by the
/// PropertySpec class, such as ReadOnly and Browsable.
///
public Attribute[] Attributes
{
get { return attributes; }
set { attributes = value; }
}
///
/// Gets or sets the category name of this property.
///
public string Category
{
get { return category; }
set { category = value; }
}
///
/// Gets or sets the fully qualified name of the type converter
/// type for this property.
///
public string ConverterTypeName
{
get { return typeConverter; }
set { typeConverter = value; }
}
///
/// Gets or sets the default value of this property.
///
public object DefaultValue
{
get { return defaultValue; }
set { defaultValue = value; }
}
///
/// Gets or sets the help text description of this property.
///
public string Description
{
get { return description; }
set { description = value; }
}
///
/// Gets or sets the fully qualified name of the editor type for
/// this property.
///
public string EditorTypeName
{
get { return editor; }
set { editor = value; }
}
///
/// Gets or sets the name of this property.
///
public string Name
{
get { return name; }
set { name = value; }
}
///
/// Gets or sets the fully qualfied name of the type of this
/// property.
///
public string TypeName
{
get { return type; }
set { type = value; }
}
}
///
/// Provides data for the GetValue and SetValue events of the PropertyBag class.
///
public class PropertySpecEventArgs : EventArgs
{
private PropertySpec property;
private object val;
///
/// Initializes a new instance of the PropertySpecEventArgs class.
///
/// The PropertySpec that represents the property whose
/// value is being requested or set.
/// The current value of the property.
public PropertySpecEventArgs(PropertySpec property, object val)
{
this.property = property;
this.val = val;
}
///
/// Gets the PropertySpec that represents the property whose value is being
/// requested or set.
///
public PropertySpec Property
{
get { return property; }
}
///
/// Gets or sets the current value of the property.
///
public object Value
{
get { return val; }
set { val = value; }
}
}
///
/// Represents the method that will handle the GetValue and SetValue events of the
/// PropertyBag class.
///
public delegate void PropertySpecEventHandler(object sender, PropertySpecEventArgs e);
///
/// Represents a collection of custom properties that can be selected into a
/// PropertyGrid to provide functionality beyond that of the simple reflection
/// normally used to query an object's properties.
///
public class PropertyBag : ICustomTypeDescriptor
{
#region PropertySpecCollection class definition
///
/// Encapsulates a collection of PropertySpec objects.
///
[Serializable]
public class PropertySpecCollection : IList
{
private ArrayList innerArray;
///
/// Initializes a new instance of the PropertySpecCollection class.
///
public PropertySpecCollection()
{
innerArray = new ArrayList();
}
///
/// Gets the number of elements in the PropertySpecCollection.
///
///
/// The number of elements contained in the PropertySpecCollection.
///
public int Count
{
get { return innerArray.Count; }
}
///
/// Gets a value indicating whether the PropertySpecCollection has a fixed size.
///
///
/// true if the PropertySpecCollection has a fixed size; otherwise, false.
///
public bool IsFixedSize
{
get { return false; }
}
///
/// Gets a value indicating whether the PropertySpecCollection is read-only.
///
public bool IsReadOnly
{
get { return false; }
}
///
/// Gets a value indicating whether access to the collection is synchronized (thread-safe).
///
///
/// true if access to the PropertySpecCollection is synchronized (thread-safe); otherwise, false.
///
public bool IsSynchronized
{
get { return false; }
}
///
/// Gets an object that can be used to synchronize access to the collection.
///
///
/// An object that can be used to synchronize access to the collection.
///
object ICollection.SyncRoot
{
get { return null; }
}
///
/// Gets or sets the element at the specified index.
/// In C#, this property is the indexer for the PropertySpecCollection class.
///
/// The zero-based index of the element to get or set.
///
/// The element at the specified index.
///
public PropertySpec this[int index]
{
get { return (PropertySpec)innerArray[index]; }
set { innerArray[index] = value; }
}
///
/// Adds a PropertySpec to the end of the PropertySpecCollection.
///
/// The PropertySpec to be added to the end of the PropertySpecCollection.
/// The PropertySpecCollection index at which the value has been added.
public int Add(PropertySpec value)
{
int index = innerArray.Add(value);
return index;
}
///
/// Adds the elements of an array of PropertySpec objects to the end of the PropertySpecCollection.
///
/// The PropertySpec array whose elements should be added to the end of the
/// PropertySpecCollection.
public void AddRange(PropertySpec[] array)
{
innerArray.AddRange(array);
}
///
/// Removes all elements from the PropertySpecCollection.
///
public void Clear()
{
innerArray.Clear();
}
///
/// Determines whether a PropertySpec is in the PropertySpecCollection.
///
/// The PropertySpec to locate in the PropertySpecCollection. The element to locate
/// can be a null reference (Nothing in Visual Basic).
/// true if item is found in the PropertySpecCollection; otherwise, false.
public bool Contains(PropertySpec item)
{
return innerArray.Contains(item);
}
///
/// Determines whether a PropertySpec with the specified name is in the PropertySpecCollection.
///
/// The name of the PropertySpec to locate in the PropertySpecCollection.
/// true if item is found in the PropertySpecCollection; otherwise, false.
public bool Contains(string name)
{
foreach(PropertySpec spec in innerArray)
if(spec.Name == name)
return true;
return false;
}
///
/// Copies the entire PropertySpecCollection to a compatible one-dimensional Array, starting at the
/// beginning of the target array.
///
/// The one-dimensional Array that is the destination of the elements copied
/// from PropertySpecCollection. The Array must have zero-based indexing.
public void CopyTo(PropertySpec[] array)
{
innerArray.CopyTo(array);
}
///
/// Copies the PropertySpecCollection or a portion of it to a one-dimensional array.
///
/// The one-dimensional Array that is the destination of the elements copied
/// from the collection.
/// The zero-based index in array at which copying begins.
public void CopyTo(PropertySpec[] array, int index)
{
innerArray.CopyTo(array, index);
}
///
/// Returns an enumerator that can iterate through the PropertySpecCollection.
///
/// An IEnumerator for the entire PropertySpecCollection.
public IEnumerator GetEnumerator()
{
return innerArray.GetEnumerator();
}
///
/// Searches for the specified PropertySpec and returns the zero-based index of the first
/// occurrence within the entire PropertySpecCollection.
///
/// The PropertySpec to locate in the PropertySpecCollection.
/// The zero-based index of the first occurrence of value within the entire PropertySpecCollection,
/// if found; otherwise, -1.
public int IndexOf(PropertySpec value)
{
return innerArray.IndexOf(value);
}
///
/// Searches for the PropertySpec with the specified name and returns the zero-based index of
/// the first occurrence within the entire PropertySpecCollection.
///
/// The name of the PropertySpec to locate in the PropertySpecCollection.
/// The zero-based index of the first occurrence of value within the entire PropertySpecCollection,
/// if found; otherwise, -1.
public int IndexOf(string name)
{
int i = 0;
foreach(PropertySpec spec in innerArray)
{
if(spec.Name == name)
return i;
i++;
}
return -1;
}
///
/// Inserts a PropertySpec object into the PropertySpecCollection at the specified index.
///
/// The zero-based index at which value should be inserted.
/// The PropertySpec to insert.
public void Insert(int index, PropertySpec value)
{
innerArray.Insert(index, value);
}
///
/// Removes the first occurrence of a specific object from the PropertySpecCollection.
///
/// The PropertySpec to remove from the PropertySpecCollection.
public void Remove(PropertySpec obj)
{
innerArray.Remove(obj);
}
///
/// Removes the property with the specified name from the PropertySpecCollection.
///
/// The name of the PropertySpec to remove from the PropertySpecCollection.
public void Remove(string name)
{
int index = IndexOf(name);
RemoveAt(index);
}
///
/// Removes the object at the specified index of the PropertySpecCollection.
///
/// The zero-based index of the element to remove.
public void RemoveAt(int index)
{
innerArray.RemoveAt(index);
}
///
/// Copies the elements of the PropertySpecCollection to a new PropertySpec array.
///
/// A PropertySpec array containing copies of the elements of the PropertySpecCollection.
public PropertySpec[] ToArray()
{
return (PropertySpec[])innerArray.ToArray(typeof(PropertySpec));
}
#region Explicit interface implementations for ICollection and IList
///
/// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
///
void ICollection.CopyTo(Array array, int index)
{
CopyTo((PropertySpec[])array, index);
}
///
/// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
///
int IList.Add(object value)
{
return Add((PropertySpec)value);
}
///
/// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
///
bool IList.Contains(object obj)
{
return Contains((PropertySpec)obj);
}
///
/// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
///
object IList.this[int index]
{
get
{
return ((PropertySpecCollection)this)[index];
}
set
{
((PropertySpecCollection)this)[index] = (PropertySpec)value;
}
}
///
/// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
///
int IList.IndexOf(object obj)
{
return IndexOf((PropertySpec)obj);
}
///
/// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
///
void IList.Insert(int index, object value)
{
Insert(index, (PropertySpec)value);
}
///
/// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
///
void IList.Remove(object value)
{
Remove((PropertySpec)value);
}
#endregion
}
#endregion
#region PropertySpecDescriptor class definition
private class PropertySpecDescriptor : PropertyDescriptor
{
private PropertyBag bag;
private PropertySpec item;
public PropertySpecDescriptor(PropertySpec item, PropertyBag bag, string name, Attribute[] attrs) :
base(name, attrs)
{
this.bag = bag;
this.item = item;
}
public override Type ComponentType
{
get { return item.GetType(); }
}
public override bool IsReadOnly
{
get { return (Attributes.Matches(ReadOnlyAttribute.Yes)); }
}
public override Type PropertyType
{
get { return Type.GetType(item.TypeName); }
}
public override bool CanResetValue(object component)
{
if(item.DefaultValue == null)
return false;
else
return !this.GetValue(component).Equals(item.DefaultValue);
}
public override object GetValue(object component)
{
// Have the property bag raise an event to get the current value
// of the property.
PropertySpecEventArgs e = new PropertySpecEventArgs(item, null);
bag.OnGetValue(e);
return e.Value;
}
public override void ResetValue(object component)
{
SetValue(component, item.DefaultValue);
}
public override void SetValue(object component, object value)
{
// Have the property bag raise an event to set the current value
// of the property.
PropertySpecEventArgs e = new PropertySpecEventArgs(item, value);
bag.OnSetValue(e);
}
public override bool ShouldSerializeValue(object component)
{
object val = this.GetValue(component);
if(item.DefaultValue == null && val == null)
return false;
else
return !val.Equals(item.DefaultValue);
}
}
#endregion
private string defaultProperty;
private PropertySpecCollection properties;
///
/// Initializes a new instance of the PropertyBag class.
///
public PropertyBag()
{
defaultProperty = null;
properties = new PropertySpecCollection();
}
///
/// Gets or sets the name of the default property in the collection.
///
public string DefaultProperty
{
get { return defaultProperty; }
set { defaultProperty = value; }
}
///
/// Gets the collection of properties contained within this PropertyBag.
///
public PropertySpecCollection Properties
{
get { return properties; }
}
///
/// Occurs when a PropertyGrid requests the value of a property.
///
public event PropertySpecEventHandler GetValue;
///
/// Occurs when the user changes the value of a property in a PropertyGrid.
///
public event PropertySpecEventHandler SetValue;
///
/// Raises the GetValue event.
///
/// A PropertySpecEventArgs that contains the event data.
protected virtual void OnGetValue(PropertySpecEventArgs e)
{
if(GetValue != null)
GetValue(this, e);
}
///
/// Raises the SetValue event.
///
/// A PropertySpecEventArgs that contains the event data.
protected virtual void OnSetValue(PropertySpecEventArgs e)
{
if(SetValue != null)
SetValue(this, e);
}
#region ICustomTypeDescriptor explicit interface definitions
// Most of the functions required by the ICustomTypeDescriptor are
// merely pssed on to the default TypeDescriptor for this type,
// which will do something appropriate. The exceptions are noted
// below.
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
string ICustomTypeDescriptor.GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
string ICustomTypeDescriptor.GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
// This function searches the property list for the property
// with the same name as the DefaultProperty specified, and
// returns a property descriptor for it. If no property is
// found that matches DefaultProperty, a null reference is
// returned instead.
PropertySpec propertySpec = null;
if(defaultProperty != null)
{
int index = properties.IndexOf(defaultProperty);
propertySpec = properties[index];
}
if(propertySpec != null)
return new PropertySpecDescriptor(propertySpec, this, propertySpec.Name, null);
else
return null;
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
// Rather than passing this function on to the default TypeDescriptor,
// which would return the actual properties of PropertyBag, I construct
// a list here that contains property descriptors for the elements of the
// Properties list in the bag.
ArrayList props = new ArrayList();
foreach(PropertySpec property in properties)
{
ArrayList attrs = new ArrayList();
// If a category, description, editor, or type converter are specified
// in the PropertySpec, create attributes to define that relationship.
if(property.Category != null)
attrs.Add(new CategoryAttribute(property.Category));
if(property.Description != null)
attrs.Add(new DescriptionAttribute(property.Description));
if(property.EditorTypeName != null)
attrs.Add(new EditorAttribute(property.EditorTypeName, typeof(UITypeEditor)));
if(property.ConverterTypeName != null)
attrs.Add(new TypeConverterAttribute(property.ConverterTypeName));
// Additionally, append the custom attributes associated with the
// PropertySpec, if any.
if(property.Attributes != null)
attrs.AddRange(property.Attributes);
Attribute[] attrArray = (Attribute[])attrs.ToArray(typeof(Attribute));
// Create a new property descriptor for the property item, and add
// it to the list.
PropertySpecDescriptor pd = new PropertySpecDescriptor(property,
this, property.Name, attrArray);
props.Add(pd);
}
// Convert the list of PropertyDescriptors to a collection that the
// ICustomTypeDescriptor can use, and return it.
PropertyDescriptor[] propArray = (PropertyDescriptor[])props.ToArray(
typeof(PropertyDescriptor));
return new PropertyDescriptorCollection(propArray);
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion
}
///
/// An extension of PropertyBag that manages a table of property values, in
/// addition to firing events when property values are requested or set.
///
public class PropertyTable : PropertyBag
{
private Hashtable propValues;
///
/// Initializes a new instance of the PropertyTable class.
///
public PropertyTable()
{
propValues = new Hashtable();
}
///
/// Gets or sets the value of the property with the specified name.
/// In C#, this property is the indexer of the PropertyTable class.
///
public object this[string key]
{
get { return propValues[key]; }
set { propValues[key] = value; }
}
///
/// This member overrides PropertyBag.OnGetValue.
///
protected override void OnGetValue(PropertySpecEventArgs e)
{
e.Value = propValues[e.Property.Name];
base.OnGetValue(e);
}
///
/// This member overrides PropertyBag.OnSetValue.
///
protected override void OnSetValue(PropertySpecEventArgs e)
{
propValues[e.Property.Name] = e.Value;
base.OnSetValue(e);
}
}
}