PropertyGrid - Collection Edition / Wrapper - c#

I have a complex kind of property I want to edit in a PropertyGrid.
interface IInterface{}
abstract class Base : IInterface{}
class A : Base{}
class B : Base{}
These class represent what can be stored in the property (The content of these class does not matter).
// The Property to be displayed in the PropertyGrid
class Property
{
List<Base> MyListOfObjects {get;set;}
}
I managed to create a derived class of System.ComponentModel.Design.CollectionEditor which allows me to add different kind of datas, using [Editor(typeof(MyCollectionEditor), typeof(UITypeEditor))] attribute in the collection property.
class MyCollectionEditor : CollectionEditor
{
public MyCollectionEditor(Type type) : base(type)
{
}
#region Overrides of CollectionEditor
protected override Type[] CreateNewItemTypes()
{
base.CreateNewItemTypes();
// [EDIT assembly, see below]
var types = (from t in Assembly.GetAssembly(typeof(IInterface)).GetTypes()
where t.GetInterfaces().Contains(typeof (IInterface)) && !t.IsAbstract
select t).ToArray();
return types;
}
protected override Type CreateCollectionItemType()
{
return typeof(A); // 1st problem
}
}
First Problem: The only solution I found to be able to edit the objects is to give a concrete child class type in CreateCollectionItemType(). Why? How to avoid that?
Second Problem: I now want to use a wrapper to give this property to the propertyGrid item. Instead of having the property attributes ([Category("General")] for instance) in the model, I want to put them in a wrapper.
It works fine for everything but the collection.
Here is how I did it:
class abstract WrapperBase<T>
{
T WrappedObject{get;set;}
}
class PropertyWrapper:WrapperBase<Property>
{
List<Base> MyListOfObjects
{
get{return WrappedObject.MyListOfObjects;}
set{WrappedObject.MyListOfObjects=value;}
}
}
With this, the collection editor won't let me add objects to this Collection, and the dropdown that was available to add a specific kind of object is gone.
Any idea? Thanks in advance!
[EDIT]
The second part of the problem is solved: Since the wrapper is located in another assembly, I was not looking in the right place for the implementations of IInterface.

CreateNewItemTypes is good. in CreateCollectionItemType return the base type. i think that should work.

Related

Collection of types which implement a specific interface

I'm trying to create a class with the name ForumHolderAdminController. ForumHolderAdminController provides a collection of controller types to the parent class CmsAdminController.
I have the following code:
public abstract class CmsAdminController : Controller {
// The type of child controllers allowed
protected Collection<Type> AllowedChildren {
get { return null; }
}
}
public class ForumHolderAdminController : CmsAdminController {
protected new Collection<Type> AllowedChildren {
get {
Collection<Type> allowedChildren = new Collection<Type> {
typeof(ThreadHolderController)
};
return allowedChildren;
}
}
}
I would like to restrict developers to passing a collection of types that implement the IController interface. Something similar to the following:
protected new Collection<IController> AllowedChildren {
get {
Collection<IController> allowedChildren = new Collection<IController> {
typeof(ThreadHolderController)
};
return allowedChildren;
}
}
Obviously the code example won't work because there is no instance being created. But I would like something similar to this where you don't have to create an instance of an object, you just have to pass the type.
I did see the following question which appears to be somewhat relevant, however one of the comments suggests using static analysis of the type before adding it to the collection:
Type-safe collection of Type class with defined base type
If I have to perform a static analysis this leaves me with a problem. If the developer passes a type that hasn't implemented the IController interface we won't know there is a problem with the code until it is executed. I would prefer it there was a compile error preventing developers from passing a collection of types where one or more don't implement the IController interface.
Therefore, is it possible to restrict developers to passing a collection of types that implement the IController interface?
You could come pretty close to what you want to do by returning a custom class that wraps the Type, and which can only be instantiated for generic types that implement IController:
public class ControllerTypeWrapper<T> : ControllerTypeWrapper
where T : IController
{
public Type Type {get {return typeof(T);}}
}
public class ControllerTypeWrapper
{
// This should only be extended by ControllerTypeWrapper<T>
internal ControllerTypeWrapper(){}
}
Then your AllowedChildren property should return these wrappers, and whatever's consuming it can simply use the.Type` property off of the results:
protected new IReadOnlyCollection<ControllerTypeWrapper> AllowedChildren {
get {
return new List<ControllerTypeWrapper> {
new ControllerTypeWrapper<ThreadHolderController>()
};
}
}
Note: You probably don't actually intend to have this property be new. Consider making the parent class's property abstract so you can force the child classes to override it.
Another option would be to use Alex Voskresenskiy's approach, with a RegisterType<T>() method, but in that case you probably want that method to be protected, and expect your child class's constructor to call into RegisterType<>() with whatever child types you want to allow. The down-side to this would be that you're doing this work every time the controller is constructed, whereas it's likely you only need it once.
There are likely other, even better, options, like using custom attributes and using a simple unit test to check that all the attributes on all your controllers have the appropriate types in them. But it's hard to say without knowing more about how you intend to use this data.
I'm not sure i got you right, but you can do something like this:
public abstract class CmsAdminController : Controller
{
private Collection<Type> _allowedChildren = new Collection<Type>();
// The type of child controllers allowed
protected Collection<Type> AllowedChildren
{
get {return _allowedChildren; }
}
public void Registertype<T>() where T : IController
{
_allowedChildren.Add(typeof(T));
}
}
The only thing you should also do is to restrict Add on _allowedChildren, for example you can return IEnumerable instead of Collection

What is a good way to deal with multiple object types in the same form?

I have an abstract base class and two derived classes. The base class contains 6 properties which all can be maintained on a form.
The two derived classed both have 1 extra property. Those two properties can also be maintained on the same form.
In my form I have now code like this:
btnSomething.visible = (myObject is DerivedA);
pnlPanel.visible = !(myObject is DerivedA);
if(myObject is DerivedA)
myBindingSource.DataSource = myObject as DerivedA
mySecondBindingSource = myObject;
I am not very happy with this approach, it smells. So my question is, what is a neat/good way to make this more OO? Because it is possibly that in the future DerivedC comes in...
I think this approach breaks the OCP principle (and probably other principles)
You can use polymorphism and inheritance here:
Define an interface
interface ICommonFeatures
{
bool ContainsFoo {get;}
//yak-yak
}
Then your derived classes implement it
class DerivedA: ICommonFeatures
{
bool ContainsFoo {get {return true;}}
//so-and-so
}
class DerivedB: ICommonFeatures
{
bool ContainsFoo {get {return false;}}
//this-and-that
}
And when you use it, you deal only with the interface
ICommonFeatures foo = new DerivedB();
btnSomething.visible = foo.ContainsFoo;
pnlPanel.visible = foo.Prop2;
myBindingSource.DataSource = foo.CurrentDataSource
A crazy idea would be make the UI extensible.
You could make a form implement a base form.
Then in the derived form class you would only insert the missing controls and behavior for the its model class.
In the derived model class or library you could have some sort binding to the correct form.
A good approach for this would be follow some MVP principles.
Hope it helps you somehow..
I would declare an abstract boolean method/property for each control that need to behave according to the underlying type.
For instance
// to handle pnlPanel.visible = !(myObject is DerivedA);
abstract bool SupportsPanel{get;}
As for your binding sources, I would also provide some virtual BindingSource and SecondBindingSource properties.
Maybe something like (purely an example)
public abstract class BaseClass
{
// All your exising class declaration here
public virtual object BindingSource
{
get
{
// By default, a BaseClass is not valid as a binding source
return null;
}
}
public virtual object SecondBindingSource
{
get
{
// By default, a BaseClass is a valid Second Binding source
return this;
}
}
}
public class DerivedA : BaseClass
{
// All your exising class implementation here
public override object BindingSource
{
get
{
// For DerivedA, the data sourse is itself.
// other classes might have their own implementations.
return this;
}
}
// No need to override SecondBindingSource as the BaseClass one works as expected.
}
So, your code could stop caring about the object type and look like:
myBindingSource.DataSource = myObject.BindingSource;
mySecondBindingSource = myObject.SecondBindingSource;
Hope this helps.

Why would you mask a base class member?

I have just learned how to mask a base class member (using new) but am missing the point as to why I would want to do that. Does masking provide us with a certain level of protection as is the case in using encapsulation? Please advise.
You will very rarely use "new" to mask a base class member.
It's mainly used for the cases where the derived class had the member first, and then it was added to the base class --- the same name for a different purpose. The new is there to that you acknowledge that you know you are using it differently. When a base member is added in C++, it just silently merges the existing method into the inheritance chain. In C#, you will have to choose between new and override, to show you know what is happening.
It's not just used for masking. It actually breaks the inheritance chain, so if you call the base class method, the method in the derived class will not be called (just the one in the base class).
You're essentially creating a new method that has nothing to do with the base class method. Hence the "new" keyword.
Keeping that in mind the "new" keyword can be used if you want to define a method with the same signature as a base type method, but having a different return type.
The only valid safe examples that I've come across is being more specific with return types or providing a set accessor on a property. I'm not saying those are the only ones, but that's all I've found.
For example, suppose you have a very simple base that looks like this:
public abstract class Base
{
public string Name { get; protected set; }
public Base(string name)
{ Name = name; }
}
You could have a derived that looks more like this:
public class Derived : Base
{
public new string Name
{
get { return base.Name; }
set { base.Name = value; }
}
public Derived(string name) : base(name)
{ }
}
Assuming business rules allows this one specific Derived to have a changeable name, I believe this is acceptable. The problem with new is that it changes behavior depending on what type the instance is viewed as. For example, if I were to say:
Derived d = new Derived("Foo");
d.Name = "Bar";
Base b = d;
b.Name = "Baz"; // <-- No set available.
In this trivial example, we're fine. We are overriding the behavior with new, but not in a breaking way. Changing return types requires a bit more finesse. Namely, if you use new to change a return type on a derived type, you shouldn't allow that type to be set by the base. Check out this example:
public class Base
{
public Base(Base child)
{ Child = child; }
public Base Child { get; private set; }
}
public class Derived
{
public Derived(Derived child) : base(child)
{ }
public new Derived Child
{ get { return (Derived)base.Child; } }
}
If I could set Child on the Base class, I could have a casting problem in the Derived class. Another example:
Derived d = new Derived(someDerivedInstance);
Base b = d;
var c = b.Child; // c is of type Base
var e = d.Child; // e is of type Derived
I can't break any business rules by treating all of my Derived classes as Bases, it's just convenient to not type check and cast.
I have just learned how to mask a base class member (using new)
FYI this feature is usually called "hiding" rather than "masking". I think of "masking" as clearing bits in a bit array.
am missing the point as to why I would want to do that.
Normally you don't want to. For some reasons to use and not use this feature, see my article on the subject from 2008:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx
Does masking provide us with a certain level of protection as is the case in using encapsulation?
No, it does not.
What you are referring to is called Name Hiding. It is mostly a convenience feature. If you are inheriting from a class for which you do not control the source using new will let you change the behavior of a method even if it wasn't declared as virtual (or completely change the signature if it is virtual). The new keyword simply suppresses a compiler warning. You are basically informing the compiler that you are intentionally hiding the method from a parent class.
Delphi had the reintroduce keyword for the same reason.
What does this buy you other than a suppressed warning? Not a whole lot. You can't access the new method from a parent class. You can access it from an interface if your child class directly implements the interface (as apposed to inheriting it from its parent class). You can still call the parent class' member from the child. Any additional descendants of your class will inherit the new member rather than the one in the parent.
This is actually called member hiding. There are a couple of common scenarios where this can be appropriately used.
It allows you to work around versioning issues in which either the base or derived class author unwittingly creates a member name that collides with an existing identifier.
It can be used to simulate covariance on return types.
Regarding the first point...it is possible that an author of a base class could later add a member with the same name as an exisiting member in a derived class. The base class author may not have an knowledge of the derived classes and thus there is no expectation that she should avoid name collisions. C# supports the independent evolution of class hierarchies using the hiding mechanisms.
Regarding the second point...you may want a class to implement an interface that dictates a certain method signature and so you are locked into returning instances of a certain type only while at the same time you have subclassed that type and would really like for callers to see the concrete type instead. Consider this example.
public interface IFoo { }
public class ConcreteFoo { }
public abstract class Base
{
private IFoo m_Foo;
public Base(IFoo x) { m_Foo = x; }
public IFoo Foo { get { return m_Foo; } }
}
public class Derived
{
public Derived(ConcreteFoo x) : base(x) { }
public new ConcreteFoo Foo { get { return (ConcreteFoo)base.Foo; } }
}

How would you approach this design?

I have ControlA which accepts an IInterfaceB which has a property of type
List<unknownType>
In an event of ControlA i need to add a new instance of unknownType to the List in IInterfaceB...
unknownType needs specific properties so i immediately thought it could be an interface, but quickly realised interfaces cannot be instantiated...
How would you design this system?
EDIT the current inheritance chain looks like this:
topLevelClass -> baseObject -> IBaseObject (which is implemented in topLevelClass)
so if i added a new class to the chain it would need to do the inheriting and implementing which would be impossible (afaik)
If I'm interpreting this correctly, you could add a constraint on unknownType to be of some interface that contains the properties you need:
class ControlA
{
void Frob<T>(IInterfaceB<T> something) where T : IHasSomeProperties, new()
{
something.ListOfT.Add(new T() { SomeProperty = 5 });
something.ListOfT.Add(new T() { SomeProperty = 14 });
}
}
Would a restriction on the type work?
List<T> where T : IInterface
Your specification isn't specific enough to answer well, but try putting constraints on T.
public interface IInterfaceB<T>
where T : new()
{
List<T> Whatever { get; }
}
This allows you to do this:
T iDoNotCare = new T();
Why does List have to be an unknowntype? Why can't it be a real class, the has the real properties you need with a constructor for you to instantiate? If you need to extend that class, you can then inherit from it. Based on the information you're providing, if all you need is a few properties in the class that goes into this List, then a good old class should do the trick.

Overloading BindingList<T> of parent property with a subclass of T

I am having some trouble with an idea that at its simplest seems like it should work.
I am trying to overload a Property of Type BindingList<T> in a subclass with a BindingList of <subclasss T>. There are ways I can get around this but it seems the 'nicest' way would be without any direct casting. I have tried a bunch of options and have some solutions but I am not particularly happy with any of them.
Is there a best approach to this? A simple code example might be the best descriptor
In this example below, I want to derive a fruitbowl to contain only apples but use the same property name to access this BindingList<> of Apples (in the case of the subclass; generic fruit in the case of the Super class).
--------Example-------
class Fruit{}
class Apple: Fruit {}
class FruitBowl
{
protected BindingList<Fruit> m_aFruits;
public BindingList<Fruit> Fruits
{
get {return m_aFruits;}
}
}
class AppleBowl : FruitBowl
{
public BindingList<Apple> Fruits
{
get {return m_aFruits;}
}
}
What you're attempting to do is known as Co/Contra Variance. Unfortunately this is not supported on concrete types in C# (available on interfaces only for C# 4.0). Given the implementation of BindingList<T> it is not possible to do what you want and maintain only a single list.
You can attempt to fake this in several ways. One way to get around this is to only use IEnumerable<T> on the sub class. In this case a simple LINQ query will do the trick.
class AppleBowl : FruitBowl
{
public IEnumerableApple> TypedFruits
{
get {return base.Fruits.Cast<Apple>();}
}
}
class FruitBowl<T> where T : Fruit //this requires T to inherit from Fruit
{
protected BindingList<T> Fruits;
}
class AppleBowl : FruitBowl<Apple>
{
//AppleBowl will have an inherited property Fruits
//of type BindingList<Apple>
}

Categories

Resources