5,664,339 members and growing! (15,157 online)
Email Password   helpLost your password?
Development Lifecycle » Design and Architecture » General     Intermediate

Dynamic property attribute evaluation at run and desing time

By mileni

Ever wanted to hide, propertect properties at design or runtime using other property value? Here is the answer!!!
C# 2.0, C#, Windows, .NET, .NET 1.1, .NET 2.0VS.NET2003, Visual Studio, Dev

Posted: 21 Mar 2007
Updated: 21 Mar 2007
Views: 15,003
Bookmarked: 21 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
10 votes for this Article.
Popularity: 4.04 Rating: 4.04 out of 5
2 votes, 20.0%
1
0 votes, 0.0%
2
1 vote, 10.0%
3
0 votes, 0.0%
4
7 votes, 70.0%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article
Screenshot - image1.png

When Formatable is False, only Text is visible

Screenshot - image2.png

But when Formatable is True, Text is protected and Format shows up ;)

Introduction

In my work very often I have to resolve this kind of problems so after some reading, copying, googling, etc... Wow idea comes up!

Background

Implementing ICustomTypeDescriptor interface on any class we can provide properties to PropertyGrid control in dynamic way. So lets code that interface.

public class SomeClass : ICustomTypeDescriptor
{
    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return TypeDescriptor.GetEvents(this, attributes, true);
    }
    /* ... so we arrive at ... */
    public PropertyDescriptorCollection GetProperties()
    {
        // use new implemented class to get properties

        return DynamicTypeDescriptor.GetProperties(this);
    }
} 
So, what is DynamicTypeDescriptor class here for? This class substitutes standard TypeDescriptor.GetProperties(...) behaviour.
public static PropertyDescriptorCollection GetProperties(object component) 
{
    // hold all properties found

    PropertyInfo[] propsInfo = component.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance);
    ArrayList list = new ArrayList(propsInfo.Length);
    // loop properties        

    foreach(PropertyInfo prop in propsInfo) 
    {
        // get all property attributes and check for "dynamics"

        ArrayList attributeList = new ArrayList();
        foreach(Attribute attrib in prop.GetCustomAttributes(true)) 
        {
            // if is dynamic one then evaluate it

            if (attrib is DependsOnPropertyAttribute) 
                attributeList.Add(((DependsOnPropertyAttribute)attrib).Evaluate(component));
            else
                attributeList.Add(attrib);
        }
        list.Add(new PropertyInfoDescriptor(prop, (Attribute[])attributeList.ToArray(typeof(Attribute))));
    }
    return new PropertyDescriptorCollection((PropertyDescriptor[])list.ToArray(typeof(PropertyDescriptor)));
}

You may said, but what DependsOnPropertyAttribute stands for?

/// <summary>

/// Base class for all dynamic attributes.

/// Only properties can use this attribute.

/// </summary>

[AttributeUsage(AttributeTargets.Property)]
public abstract class DependsOnPropertyAttribute : Attribute
{
    /// <summary>

    /// Create new instance of class

    /// </summary>

    /// <param name="expression">Property name</param>

    protected DependsOnPropertyAttribute(string property) : base()
    {
        _property = property;
        _index    = null;
    }
    /// <summary>

    /// Create new instance of class

    /// </summary>

    /// <param name="property">Property name</param>

    /// <param name="index">Property element index</param>

    protected DependsOnPropertyAttribute(string property, int index) 
    {
        _property = property;
        _index    = new object[] {index};
    }
        
    private string   _property;
    private object[] _index;
        
    /// <summary>

    /// Evaluate attribute using property container supplied

    /// </summary>

    /// <param name="container">Object that contains property to evaluate</param>

    /// <returns>Dynamically evaluated attribute</returns>

    public Attribute Evaluate(object container) 
    {
        return OnEvaluateComplete(RuntimeEvaluator.Eval(container, _property, _index));
    }
    /// <summary>

    /// Specific dynamic attribute check implementation

    /// </summary>

    /// <param name="value">Evaluated value</param>

    /// <returns>Dynamically evaluated attribute</returns>

    protected abstract Attribute OnEvaluateComplete(object value);

    private class RuntimeEvaluator 
    {
        public static object Eval(object container, string property, object[] index) 
        {
            PropertyInfo pInfo = container.GetType().GetProperty(property);
            if (pInfo != null)
                return pInfo.GetValue(container, index);
            
            return null;
        }
    }
}

This class defines abstract implemenentation for all DynamicAttributes. In my example there are two implemented attributes: DynamicBrowsableAttribute and DynamicReadOnlyAttribute.

Sample implementation for abstract OnEvaluateComplete method:

protected override Attribute OnEvaluateComplete(object value)
{
    Attribute output;
    try
    {
        // check if value is provided

        if (value == null) 
            value = false; // asume default

        // create attribute

        output = new ReadOnlyAttribute((bool)value);
    }
    catch
    {
        output = new ReadOnlyAttribute(false);
    }
    return output;
}

Using the code

To use code you will have to create some class with public properties. On property that others depends on, insert RefreshProperties(RefreshProperties.All) attribute so property grid will be auto refreshed and will requery your properties. To provide dynamic functionality implement ICustomTypeDescriptor interface in your class. Now on you dynamically provide properties to property grid, easy yeah!

Insert DynamicAttribute on dynamic properties like this DynamicBrowsable("property name"), where property name is substituted with name of property that this one depends on. In my case property Format have DynamicBrowsable("Formatable") attribute set.

So now you will have to create instance of your class and select it in property grid control.

Points of Interest

You can see how to implement ICustomTypeDescriptor interface, how to provide new Attributes and how to play with PropertyGrid control.

History

21/03/2007 - First release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

mileni


Working as consultant for "IT punto COM", italian company situated in Milan.
14 years of professional programming and software designing experience.
Currently interested in VB.NET, C# programming.
Occupation: Web Developer
Location: Italy Italy

Other popular Design and Architecture articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 6 of 6 (Total in Forum: 6) (Refresh)FirstPrevNext
GeneralAlready done 2.5 years ago?memberwout de zeeuw18:38 21 Mar '07  
GeneralRe: Already done 2.5 years ago?membermileni0:21 22 Mar '07  
GeneralRe: Already done 2.5 years ago?memberwout de zeeuw4:47 22 Mar '07  
GeneralRe: Already done 2.5 years ago?membervince_formica6:43 17 Oct '07  
GeneralRe: Already done 2.5 years ago?memberwout de zeeuw6:56 17 Oct '07  
GeneralRe: Already done 2.5 years ago?membercrabby.net11:14 10 Jan '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 21 Mar 2007
Editor:
Copyright 2007 by mileni
Everything else Copyright © CodeProject, 1999-2008
Web12 | Advertise on the Code Project