views:

72

answers:

2

I have different sets of custom Winforms controls all deriving from Control such as:

CalculatorPanel, GraphPanel, DisplayPanel, etc : Control

I use a single Form to display one or more of these sets depending on what the user wants to see.

All of them has a member called:

Input

where the type is different such as:

CalculatorInput, GraphInput, DisplayInput, etc.

How do I store them in a list or some other collection where I can call the Input property without any problem?

Should I use a common interface for each? Then it has to be generic. How will I specify the type?

Right now I use something like this to add/remove controls:

Panels = Dictionary <Enum, Control> ...
Panels.Add (PanelType.Calculator, new CalculatorInput ().Controls);
...

so later I can say:

Form.Add/RemoveControls (Panels[PanelType.Calculator])

but how would I set their Input property when I need to at runtime. So if the user switches to the GraphPanel, I want to be able to set it's Input right after I added its controls to the Form.

Is there a design pattern or a technique to solve this?

EDIT: Properties of each input type (no methods) are as follows:

CalculatorInput:
.Result
.LastOperation
...

GraphInput:
.Result
.SelectedNode
...

DisplayInput:
.Result
.CurrentColor
...

Basically these inputs are just types to be bound to the appropriate UI. So if the UI has some properties, they are bound to these input, which is why when I assign a new input, the UI will update automatically.

EDIT2:

So all these inputs are separate no inheritance, etc.

But are defined in appropriate rollouts as follows:

class CalculatorPanel
{
    CalculatorInput Input
}

class GraphPanel
{
    GraphInput Input
}

class DisplayPanel
{
    DisplayInput Input
}
A: 

Since the inputs are essentially separate, they could implement an interface for the small amount of common functionality, but it probably wouldn't accomplish much (it would help to know the data types of the input class members). To get access to the non-common functionality (which is most of the input objects), you'll still need extra logic to get things working:

if (currentControl is CalculatorPanel)
{
    CalculatorInput input = (currentControl as CalculatorPanel).Input;
    // ...
}
else if (currentControl is GraphPanel)
{
}
etc.
Jon Seigel
the pointer of interfaces is to allow a contract from common calling mechanism from dispirit types. why would calling an interface method be a bad design point here.
rerun
What, that is the whole point of interface, they clearly belong to the same supertype, namely "INPUT".
epitka
The OP did not make it clear whether or not the inputs share common functionality, so given the names of the classes, I assumed they do not (how is calculator input similar to graph input?).
Jon Seigel
Thanks Jon, I was actually using a similar method to yours, just don't know if there is a better way or method to do this.
Joan Venge
Updated my answer to reflect the new information.
Jon Seigel
Thanks. The input members are different even in the case of .Result, the type is different. So basically they are like apples and oranges, except all of them are accessed by the .Input property from the Panells. That's why I was wondering if there is a better way.
Joan Venge
Yeah. Now that I read the question again, you asked "How do I store them in a list" -- the 'them' is ambiguous. You can certainly follow DRapp's answer to make an interface for the panel controls, but I'm not sure it would gain much since you can group them already (as they are `Control`-derived) and you'd have to make the interface generic, which may complicate your other code significantly.
Jon Seigel
+2  A: 

I think what you need is an INTERFACE for your Input that all classes will inherit from..

public interface MyInputInterface
{
        void YourInputFunction();
}

public class CalculatorPanel : Control, MyInputInterface
{
   ..
   ..

   void MyInputInterface.YourInputFunction()
   {
       // do your code specific to calculator panel here
   }
}

public class GraphPanel : Control, MyInputInterface
{
   ..
   ..

   void MyInputInterface.YourInputFunction()
   {
       // do your code specific to graph panel here
   }
}

Then, you can build a list of anything that implements MyInputInterface

public List<MyInputInterface> MyInputList = new List<MyInputInterface>();

and work with that list as needed... The Interface is a contract of any object utilizing it to guarantee it has the associated properties, fields, functions, etc.

DRapp
If interface is implemented explicitly then you'll need to cast to that interface to be able to see "YourInputFunction".
epitka
No, just call -- in this case object.YourInputFunction. each classes implementation will know how to act upon its own controls and surroundings... unless you are returning a generic "object" that will need to be later cast()ed. The List<> already knows it is of a control that will have the function available.
DRapp
If you are dealing with a lot of object they will already be assigned to a variable with a type of the interface.
leppie