> I am trying to solve a problem involving user-configurable "fields" on an
> object.   Typically, these fields are configured by each client, and it is
> quite easy to access them programmatically - a quick example would be:

You could/should use an Expando like this:

using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace Expando
{
    public interface IExpandoField
    {
        object Value
        {
            get;
            set;
        }

        Type Type
        {
            get;
            set;
        }
    }

    public interface IExpandoRecord
    {
        IDictionary<string, IExpandoField> Fields
        {
            get;
        }
    }

    [Serializable]
    public class ExpandoTypeDescriptor : CustomTypeDescriptor
    {
        public ExpandoTypeDescriptor(ICustomTypeDescriptor descriptor)
            : base(descriptor)
        {
            if (descriptor == null)
            {
                throw new ArgumentNullException("descriptor");
            }
        }

        public override PropertyDescriptorCollection GetProperties()
        {
            return GetProperties(null);
        }

        public override PropertyDescriptorCollection
GetProperties(Attribute[] attributes)
        {
            // once again, we just wrap them up so we get to handle them.
            ExpandoPropertyDescriptorCollection properties = new
ExpandoPropertyDescriptorCollection();

            foreach (PropertyDescriptor property in
base.GetProperties(attributes))
            {
                properties.Add(property);
            }

            return properties;
        }
    }

    [Serializable]
    public class ExpandoTypeDescriptionProvider : TypeDescriptionProvider
    {
        private TypeDescriptionProvider _base;

        public ExpandoTypeDescriptionProvider()
        {
            _base = TypeDescriptor.GetProvider(typeof(IExpandoRecord));
        }

        public override ICustomTypeDescriptor GetTypeDescriptor(Type
objectType, object instance)
        {
            // simply wrapping with our own descriptor
            return new
ExpandoTypeDescriptor(_base.GetTypeDescriptor(objectType, instance));
        }
    }

    [Serializable]
    public class ExpandoPropertyDescriptorCollection :
PropertyDescriptorCollection
    {
        public ExpandoPropertyDescriptorCollection()
            : base(null)
        {
        }

        public override PropertyDescriptor Find(string name, bool ignoreCase)
        {
            return base.Find(name, ignoreCase) ?? new
ExpandoPropertyDescriptor(name);
        }
    }

    [Serializable]
    public class ExpandoPropertyDescriptor : PropertyDescriptor
    {
        private string _name;

        public ExpandoPropertyDescriptor(string name)
            : base(name, null)
        {
            _name = name;
        }

        public override bool Equals(object obj)
        {
            ExpandoPropertyDescriptor other = obj as ExpandoPropertyDescriptor;
            return other != null && other._name.Equals(_name,
StringComparison.InvariantCultureIgnoreCase);
        }

        public override int GetHashCode()
        {
            return (base.GetHashCode() * 37) ^ _name.GetHashCode();
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override void ResetValue(object component)
        {
            // do nothing...
            return;
        }

        public override bool CanResetValue(object component)
        {
            return false;
        }

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

        public override Type ComponentType
        {
            get { return typeof(IExpandoRecord); }
        }

        public override Type PropertyType
        {
            get { return typeof(object); }
        }

        public override object GetValue(object component)
        {
            return ((IExpandoRecord)component).Fields[_name].Value;
        }

        public override void SetValue(object component, object value)
        {
            ((IExpandoRecord)component).Fields[_name].Value = value;

            OnValueChanged(component, EventArgs.Empty);
        }
    }
}


--
"Your lack of planning DOES constitute an emergency on my part... so
PLAN BETTER! "

Marc C. Brooks
http://musingmarc.blogspot.com

===================================
This list is hosted by DevelopMentor�  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to