Cannot create an instance of ...type... because it is an abstract class
When you are using the propertygrid to bind a generic list the system tends to work allowing you to add new items to the list as long as the items in List<T> are all of the exact same type.
However if the List<T> is an abstract class and you want to select which item type to add to the list you will find the following error.
What you want in this case it to be able to add any subclass of the abstract class defined as T in the list selecting the appropriate type. This can be done simply by inheriting from the CollectionEditor and letting the system know what types of object are valid for selection.
I this example rather than manually return a list we use Reflection to read all of the types defined in the assembly and determine dynamically which ones are inherited from the base class T.
Then simply decorate the list you wish to edit with the following line
[Editor(typeof(DynamicCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
For example...
/// </summary>
[Editor(typeof(DynamicCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
public List<VariableDefinitionBase> Items
{
get { return _Items; }
set { _Items = value; }
}
private List<VariableDefinitionBase> _Items = new List<VariableDefinitionBase>();
The property grid now renders
as follows, automatically displaying any subclass of them item in the list
However if the List<T> is an abstract class and you want to select which item type to add to the list you will find the following error.
Cannot create an instance of Type
because it is an abstract class.
What you want in this case it to be able to add any subclass of the abstract class defined as T in the list selecting the appropriate type. This can be done simply by inheriting from the CollectionEditor and letting the system know what types of object are valid for selection.
I this example rather than manually return a list we use Reflection to read all of the types defined in the assembly and determine dynamically which ones are inherited from the base class T.
/// <summary>
/// Provides an editor to modify a list of
variable definitions
/// </summary>
public class DynamicCollectionEditor : CollectionEditor
{
/// <summary>
/// Creates a new
collection editor
/// </summary>
/// <param name="type">The type of the collection for this editor to edit.</param>
public DynamicCollectionEditor(Type type)
: base(type)
{
ItemType = type.GetGenericArguments()[0];
}
/// <summary>
/// Gets or sets the object
type that is contained within the list
/// </summary>
public Type
ItemType;
/// <summary>
/// Determines the items
that can be created by the editor
/// </summary>
/// <returns>An array of
item types that are valid for the editor</returns>
protected override Type[] CreateNewItemTypes()
{
List<Type>
ValidTypes = new List<Type>();
Type[] Types = Assembly.GetAssembly(ItemType).GetTypes();
foreach (Type Type
in Types)
{
if (Type.IsSubclassOf(ItemType)) {
ValidTypes.Add(Type); }
}
return ValidTypes.ToArray();
}
}
[Editor(typeof(DynamicCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
For example...
/// <summary>
/// Gets or sets the items in the collection/// </summary>
[Editor(typeof(DynamicCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
public List<VariableDefinitionBase> Items
{
get { return _Items; }
set { _Items = value; }
}
private List<VariableDefinitionBase> _Items = new List<VariableDefinitionBase>();
For more information about our software see our Server Documentation page on our site
I've just realised that you might want to update the CreateNewItemTypes method to
ReplyDeleteif (Type.IsSubclassOf(ItemType) && Type.IsAbstract == false) { ValidTypes.Add(Type); }
Otherwise you can have abstract classes that derive from the original abstract class and cannot be added to the list
Dave