Vinod.S.Nair

Hi,

I am sorry if I am not able to explain my requirement in the Subject. What I want is, I have a class with two Properties like HasSubMenu, and SubMenu Collection, object of this class is bound to property grid. The class i sgiven below.

Code Snippet

class Menu

{

private bool m_HasSubMenu;

private List<Menu> m_SubMenu;

[Browsable(true)]

public bool HasSubMenu

{

get { return m_HasSubMenu; }

set { m_HasSubMenu = value; }

}

[Browsable(true)]

[ReadOnly(true)]

public List<Menu> SubMenu

{

get { return m_SubMenu; }

set { m_SubMenu = value; }

}

}

This object of this class (initially with HasSubMenu false and an empty SubMenu Collection) is bound to a property grid. Now that I have a ReadOnlyAttribute set for SubMenu property this collection is read only and user can't edit in the property grid. But what I want is if the user changes the HasSubMenu property to true I want this collection to be editable (I mean somehow I want to make this ReadOnly attribute of SubMenu property false.)

I am not able to figure out how should I do this. Any help will be highly appreciated

Regards,

Vinod S Nair



Re: .NET Base Class Library How to set a Property ReadOnly dynamically based on another property value.

nobugz

That's going to be awfully hard to do. You'll have to somehow override the return value of TypeDescriptor.GetAttributes() and dynamically add the ReadOnlyAttribute. I tried implementing the ICustomTypeDescriptor interface but failed when I could not use TypeDescriptor's methods to implement the interface methods.

Possible approaches that I didn't try is to use a base class so you can use TypeDescriptor on the base class. Or implement a TypeDescriptorProvider that has a custom GetExtendedTypeDescriptor() method. I don't really know how to do this, chance of success is murky. Note that none of MSFT's classes have this behavior.





Re: .NET Base Class Library How to set a Property ReadOnly dynamically based on another property value.

Vinod.S.Nair

Hi All,

Sorry for replying to the post so late. But I have implemented this as below mentioned. I need to write three classes and they are mentioned below.

1. Wrote a custom class DependentPropertyDescriptor deriving from PropertyDescriptor

2. Made my base object (Which will be bound to PropertyGrid) to Implement the ICustomTypeDescriptor

3. Created a DependantPropertyAttribute clas deriving from Attribute class.

The below mentioned is the relevent code for these three.

DependentPropertyAttribute.cs

Code Snippet

using System;

using System.Collections.Generic;

using System.Text;

using System.ComponentModel;

namespace MetadataWrapper

{

[AttributeUsage(AttributeTargets.All)]

public class DependantPropertyAttribute: Attribute

{

private string m_BasePropertyName;

private bool m_IsOppositeRelation;

///

/// Get the BasePropertyName whose value will be used as

/// the control value for this Property ReadOnlySetting

///

public string BasePropertyName

{

get { return m_BasePropertyName; }

}

///

/// Get the Relation with the BaseProperty. This is true

/// when the base property is true the dependent property will ReadOnly.

///

public bool IsOppositeRelation

{

get { return m_IsOppositeRelation; }

}

///

///

///

/// Name of the BaseProperty

/// Relation between the BaseProperty. If true when the base property is true the dependent property will ReadOnly.

public DependantPropertyAttribute(string baseProperty, bool oppositeRelation)

{

m_BasePropertyName = baseProperty;

m_IsOppositeRelation = oppositeRelation;

}

}

}

DependentPropertyDescriptor.cs

Code Snippet

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Reflection;

namespace MetadataWrapper

{

public class DependentPropertyDescriptor : PropertyDescriptor

{

private bool m_IsReadOnly;

private object m_ParentObject;

private PropertyInfo m_CurrentPropertyInfo;

public DependentPropertyDescriptor(object parent, PropertyInfo pInfo)

: base(pInfo.Name, (Attribute[]) pInfo.GetCustomAttributes(typeof(Attribute), true))

{

m_IsReadOnly = false;

m_ParentObject = parent;

m_CurrentPropertyInfo = pInfo;

Attribute[] attributes = (Attribute[])pInfo.GetCustomAttributes(typeof(Attribute), true);

foreach (Attribute a in attributes)

{

if (a is DependantPropertyAttribute)

{

DependantPropertyAttribute dAttribute = a as DependantPropertyAttribute;

PropertyInfo bPropertyInfo = m_ParentObject.GetType().GetProperty(dAttribute.BasePropertyName);

bool baseValue = false;

if (bPropertyInfo != null)

{

baseValue = Convert.ToBoolean(bPropertyInfo.GetValue(m_ParentObject, null));

}

m_IsReadOnly = (dAttribute.IsOppositeRelation) baseValue : !baseValue;

break;

}

else if (a is ReadOnlyAttribute)

{

ReadOnlyAttribute rAttribute = a as ReadOnlyAttribute;

m_IsReadOnly = rAttribute.IsReadOnly;

}

}

}

public override bool IsReadOnly

{

get { return m_IsReadOnly; }

}

public override bool CanResetValue(object component)

{

return false;

}

public override void ResetValue(object component) {}

public override object GetValue(object component)

{

return m_CurrentPropertyInfo.GetValue(m_ParentObject, null);

}

public override void SetValue(object component, object value)

{

m_CurrentPropertyInfo.SetValue(component, value, null);

}

public override bool ShouldSerializeValue(object component)

{

return true;

}

public override Type ComponentType

{

get { return m_CurrentPropertyInfo.DeclaringType; }

}

public override Type PropertyType

{

get { return m_CurrentPropertyInfo.PropertyType; }

}

}

}

Useful part of ICustomeTypeDescriptor.cs

Code Snippet

object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)

{

return this;

}

AttributeCollection ICustomTypeDescriptor.GetAttributes()

{

return TypeDescriptor.GetAttributes(this, true);

}

string ICustomTypeDescriptor.GetClassName()

{

return TypeDescriptor.GetClassName(this, true);

}

TypeConverter ICustomTypeDescriptor.GetConverter()

{

return TypeDescriptor.GetConverter(this, true);

}

EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()

{

return TypeDescriptor.GetDefaultEvent(this, true);

}

PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()

{

return TypeDescriptor.GetDefaultProperty(this, true);

}

object ICustomTypeDescriptor.GetEditor(Type editorBaseType)

{

return TypeDescriptor.GetDefaultProperty(editorBaseType, true);

}

EventDescriptorCollection ICustomTypeDescriptor.GetEvents()

{

return TypeDescriptor.GetEvents(this, true);

}

EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)

{

return TypeDescriptor.GetEvents(this, attributes, true);

}

string ICustomTypeDescriptor.GetComponentName()

{

return TypeDescriptor.GetComponentName(this, true);

}

PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()

{

return ((ICustomTypeDescriptor)this).GetProperties(null);

}

PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)

{

bool isFilterEnabled = (attributes != null && attributes.Length > 0);

// Create the property collection

PropertyDescriptorCollection props = new PropertyDescriptorCollection(null);

foreach(PropertyInfo propInfo in this.GetType().GetProperties())

{

DependentPropertyDescriptor dProp = new DependentPropertyDescriptor(this, propInfo);

props.Add(dProp);

}

return props;

}

The above post from nobugz and the below mentioned link helped me to achieve this. Thanks may be useful for some one.

Reference Link: http://msdn.microsoft.com/msdnmag/issues/05/04/NETMatters/

Regards,

Vinod S Nair