I have many custom classes that I am using that I will explain and post examples of. After Explaining what they all do I will try to clearly describe the conditions under which my bug is happening.
First, I am using a PropertyGrid to display the properties of several different types of objects. Because the default binding of the PropertyGrid was not what as descriptive as I wanted it to be, I created a few custom classes that I will refer to as "Display" classes. These Display classes are constructed by passing in the an object and then creating properties that return nicely formatted strings and descriptions for the public properties (and in some case methods) of the real object that was passed in.
I will demonstrate this with some abbreviated example code:
Here is an example of an object I want to Display in my PropertyGrid:
public class Joint
{
public Joint(...)
{...}
//properties
public string Name { get; set;}
public CustomObject CC { get; set;}
public List<CustomObject> Custom List { get; set;}
}
The string property "Name" displays fine in the PropertyGrid However The CustomObject and List did not display in way that seemed very user friendly to me.
So I attempted to create a solution by writing this class:
public class DisplayJoint
{
private Joint _jnt;
public DisplayJoint(Joint jnt)
{
_jnt = jnt;
}
//properties
public string Name { get { return _jnt.Name; } }
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public DisplayCustomObject CC { get { return new DisplayCustomObject(_jnt.CC); } }
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public List<CustomObject> CustomList { get; set;}
}
As you can see in the code above, I created special DisplayClasses for both my Joint class and my CustomObject class. In my project I have many, many different kinds of objects that require the same kind of overlaping Display Class properties.
Above you can see the Lines I added above the last two properties
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
This line solves my problem of displaying the CustomObject how I want to in the propertGrid(almost... more on this later). However it does not work the same way for my Custom List property. On the Custom List it expands to show only Count and capacity(The actual properties of the List) It makes sense why this is, but it was not what I wanted. I wanted to see the actual contained object within the list.
So here is my complicated solution, Taken initially from this question:
I have two classes that I am using to dynamically add objects to the propertyGrid bound list in the form of properties. The first(CustomClass) can be downloaded here. It is used to Dynamically create properties. The second class(DisplayIEnumerable) I am using is derived from the first and can be found here.
The DisplayIEnumerable class loops through the list objects and adds a property to itself with the information contained within the each object. A DisplayClass is passed in to define exactly how those objects properties should be represented within the Grid.
Up to this Point everything works great! as evidenced by this picture(picture was not created using the classes provided, Strings are formatted differently in the classes I am using, removed formatting code to help you focus on the relevant code:
Now after that long intro, the real question. Using the techniques above I would like to write a class that can dynamically handle CustomObjects that I have not written unique display classes for. I am intending to leave this code for those using the application for testing so that they can more effectively test without having to have a complete Display Class for every one of my company's CustomObjects. (there are hundreds) Instead, By binding the propertyGrid with the class below, I hope to have all the properties that are lists and CustomObjects that do have corresponding DisplayClasses to be bound in their place.
Here is the class that I have already tried and have a bug with. I have not yet tried implementing the replacement of Lists with my DisplayIEnumerable class yet, I wanted to get the basic functionality working first:
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Reflection;
using System.Collections;
using System.Windows.Forms;
internal class DisplayObject : CustomClass<T>
{
#region Variables
protected T _obj;
#endregion
#region Constructor
public DisplayObject(T obj)
{
if (obj != null)
{
try
{
Type currentType = typeof(T);
foreach (PropertyInfo propertyInfo in currentType.GetProperties())
{
Attribute[] attributes = new Attribute[1];
if (propertyInfo.GetType() is IEnumerable)
attributes[0] = new TypeConverterAttribute(typeof(ExpandableObjectConverter));
else
attributes[0] = null;
this.Add(new CustomProperty(propertyInfo.Name, propertyInfo, propertyInfo.GetType(), false, true, attributes));
}
}
catch
{
MessageBox.Show("Failure!");
}
}
}
#endregion
#region Properties
[Browsable(false)]
public object Item
{
get { return _obj; }
set { _obj = value; }
}
#endregion
}
When run, The PropertyGrid appears as it should:
However, once you click on the Expand arrow, nothing happens, and the arrow disappears:
What is wrong with the class above that is not wrong with my DisplayIEnumerable class, that causes this variance in behaviour?
I am using the DisplayObject class like this(inside a DisplayClass):
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public DisplayObject EndJoint { get { if (_member.bcEnd != null) { return new DisplayObject(_member.EndJoint); } else return null; } }
Thanks in advance! I will be very impressed if anyone makes it through this question.