Click here to Skip to main content
15,905,427 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi experts,

in an application I have a System.Windows.Forms.PropertyGrid to let user change some business model properties.
One of these properties is of an enumerated type that is often used similarly, but for a few properties, some values shall not be displayed. Therefore I created SelectiveEnumAttribute. It is used in a custom TypeConverter's GetStandardValues() method to display only the relevant enum values to the user.

This attribute-based selective hiding of enumeration values works in general, but it doesn't when editing multiple objects at the same time.

In either case, PropertyGrid.SelectedObjects = objectArray is used.

[Edit2]
Seems my first example has been too narrow. The attributes of interest for me control some of the behaviour of a custom TypeConverter. Therefore I need access to a given property's attributes from within the TypeConverter's methods.
C#
blic class MyAttribute : Attribute
{
}


public class MyTypeConverter : EnumConverter
{
    public MyTypeConverter(Type type)
        : base(type)
    { }


    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        int attributeCount = context.PropertyDescriptor.Attributes.Count;   // Set Breakpoint here.

        return base.GetStandardValuesSupported(context);
    }
}


public class MyBusinessObject
{
    public enum AllValues
    {
        FirstValue,
        SecondValue,
        ThirdValue,
        FourthValue,
        FifthValue
    }

    private AllValues _oneValue = AllValues.FirstValue;

    [MyAttribute]
    [TypeConverter(typeof(MyTypeConverter))]
    public AllValues Value
    {
        get { return (_oneValue); }
        set { _oneValue = value; }
    }
}


public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }


    protected override void OnShown(EventArgs e)
    {
        base.OnShown(e);

        MyBusinessObject business1 = new MyBusinessObject();
        MyBusinessObject business2 = new MyBusinessObject();

        //propertyGrid1.SelectedObjects = new object[] { business1 };
        propertyGrid1.SelectedObjects = new object[] { business1, business2 };
    }
}


When feeding multiple objects into PropertyGrid, the attributes attached to their properties seem to simply vanish. Even though objects are of the same type and therefore, their properties' attributes are identical (in value and even in existence).

Check this in MyTypeConverter.GetStandardValuesSupported(). When showing multiple objects in the grid, the attribute count equals zero.

As long as there is only one object to show, this attribute collection contains the attributes in question and I can access their stored values (not shown in example for simplicity).
[/Edit2]

How can I preserve the attached attribute while multiselecting objects for the PropertyGrid?
Posted
Updated 17-Jan-12 23:50pm
v3
Comments
BillWoodruff 17-Jan-12 21:41pm    
I think you'll need to show the code that is not working now, show us how it's not working. And please clarify if by multi-selecting you are referring to selecting multiple enum values (that will be 'or'd together ?) ... or what you mean, exactly, by multi-selecting.
lukeer 18-Jan-12 3:07am    
I updated my question to include an example in soure code.

In the mentioned case with multiple objects to be shown in PropertyGrid the parameter type of MyTypeConverter.GetStandardValuesSupported(context) changes to System.Windows.Forms.PropertyGridInternal.MergePropertyDescriptor.

This type has a private field private PropertyDescriptor[] descriptors, which can not be used directly due to it's access level.

But using Reflection we can gain access
C#
System.Type propertyType = context.PropertyDescriptor.GetType();
System.Reflection.FieldInfo fieldInfo = propertyType.GetField(
    "descriptors",
    System.Reflection.BindingFlags.NonPublic
    | System.Reflection.BindingFlags.Instance
);
PropertyDescriptors[] descriptors =
    (PropertyDescriptor[])(fieldInfo.GetValue(context.PropertyDescriptor));
Now we can analyze each separate PropertyDescriptor.
 
Share this answer
 
I don't know much about attributes but nosy as I am, I did some test.

private void button1_Click(object sender, EventArgs e)
        {
            propertyGrid1.SelectedObjects = new object[]{_businessObject1};
            Type t = _businessObject1.GetType();
            PropertyInfo pi = t.GetProperty("SomeValue");
            MessageBox.Show(pi.GetCustomAttributes(false)[0].ToString());
        }

        private void button2_Click(object sender, EventArgs e)
        {
            propertyGrid1.SelectedObjects = new object[] { _businessObject1, _businessObject2 };
            Type t1 = _businessObject1.GetType();
            PropertyInfo pi1 = t1.GetProperty("SomeValue");

            Type t2 = _businessObject2.GetType();
            PropertyInfo pi2 = t2.GetProperty("SomeValue");

            MessageBox.Show(pi1.GetCustomAttributes(false)[0].ToString() + "\r\n" + pi2.GetCustomAttributes(false)[0].ToString());
            
        }

In both cases I can see that the attribute still exists.
Maybe I completely misunderstand your problem.
 
Share this answer
 
Comments
lukeer 18-Jan-12 5:51am    
I've rephrased my question to better match the problem.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900