views:

135

answers:

4

I have a user control, GridMasterControl which contains (amongst other things) another control called Grid.

Now I need to inherit from Grid to create EditableGrid (to add editing functionality to the grid).

I then need to create an EditableGridMasterControl which will be identical to GridMasterControl except that it will use EditableGrid, not Grid.

Both ways I can think of to implement this have problems.

1. I could copy and paste GridMasterControl and just change Grid to EditableGrid. Bad idea (code duplication not good).

2. I could get EditableGridMasterControl to inherit from GridMasterControl, then add a virtual function CreateGrid into GridMasterControl. EditableGridMasterControl could implement this to create the EditableGrid control. This too is a very bad idea as I would need to change the designer file to create the control. I need to keep the designer file clean.

How best can I implement this?

EDIT

Just to clarify I think the crux of the problem is that Visual Studio doesnt allow you to modify the designer files it creates (or at least its a very bad idea to) and I want to be able to conditionally create a different class depending on the situation.

+3  A: 

Perhaps you could look at using a composition pattern to reuse your common functionality between your different controls.

Charlie
A: 

If the GridMasterControl is doing the same thing for either grid class, you don't need to change anything: the Grid member of the GridMasterControl can hold an EditableGrid.

Matt Ellen
How can I do this? "this.Grid = new Common.Framework.UI.Controls.Grid ();" is in the designer file. I cant change this line..
Mongus Pong
then how do you determine which type of grid to use?
Matt Ellen
If the grid is on the one batch entry screen, it should be the Editable grid. Everywhere else in the app it will be the normal grid. How to get the code to do this cleanly is what I need to work out. :)
Mongus Pong
So in the one batch entry screen give it a GridMasterControl that has an EditableGrid, in all the others give it a Grid.
Matt Ellen
Thats what I want to do. I just dont know how. In the designer file for GridMasterControl it creates Grid. How can I get it to conditionally create EditableGrid instead (whilst still allowing us to play with the layout in the VS designer)?
Mongus Pong
Do you have a different GridMasterControl for each screen? If so, you can edit the designer code for the one screen that needs the EditableGrid.
Matt Ellen
+4  A: 

Could you not have one control, EditableGridMasterControl, that has a ReadOnly property? If this is set to true you disable the editing. This gives you only one set of controls to maintain, but requires the control to be more advanced than the simple GridMasterControl.

Rune Grimstad
+1 this is the nicest solution
Charlie
I was hoping to avoid this as we only need the editable grid in one place and there is a lot of (some quite hacky) code that needs to go in to make it editable.
Mongus Pong
If you really want to avoid using the editable grid then you could wrap it in another control that exposes either of the two based on the ReadOnly setting. But normally you would be best off maintaining as little code as possible, event if it is somewhat hackish.
Rune Grimstad
The only way I can think of to do this would be to create both controls in the constructor and then show / hide the relevant one based on the setting. Both grids would still be in memory.. Whilst I dont think this would be a good idea due to having to pass on all the properties / methods, I am still curious as to how you would do this.. Sorry Im not quite getting it... I mustve been hit over the head with a stupid stick this morning..
Mongus Pong
@Fungus - you shouldn't maintain separate `Grid` and `EditableGrid` controls. Build read-only functionality into the `EditableGrid` (activated by the `ReadOnly` property on the parent), use that, and delete the basic `Grid` class.
Jeff Sternal
@Jeff, I think maybe my naming has been a bit misleading. Think of them as Grid and HackedAboutLikeHellToGetATinyPieceOfFunctionalityWeWillRarelyUseGrid. :) I really dont want to do this.
Mongus Pong
Actually, there is one more thing you could do. Let your control default to the read-only Grid, but let the grid be contained in a Panel control. Now, in your EditableGrid you add code in your constructor you add code after the call to InitializeComponent. This code removes the read-only grid by clearing the Controls collection of the panel and then adds the EditableGrid instead. You will have to add the event handler manually, but it should work ... "properly".
Rune Grimstad
+1  A: 

If you want to keep the designer file the same for both, try this: Instead of dropping the actual Grid control onto your GridMasterControl, just drop a panel as a place holder.

Then create a mandatory initialization step where the appropriate grid object is created (use an interface like IGrid). This can be done in the derived class.

Here is what I mean, of course you can implement the same pattern a few different ways. The amount of code you share between the concrete implementations of AbstractGridMasterControl can vary and depends on how similar the controls are (which I have no idea). Instead of interface IGrid, you could use a parent class - again, matters how you want to do inheritance.

interface IGrid {...}
class Grid : IGrid { ...}
class EditableGrid : IGrid { ... }

abstract class AbstractGridMasterControl
{
    protected IGrid Grid
    {
        set { this.panelControl.Controls.Add(value as Control);}
    }
}

class GridMasterConrol : AbstractGridMasterControl
{
    public GridMasterControl()
    {
        this.Grid = new Grid();
    }
}

class EditableGridMasterConrol : AbstractGridMasterControl
{
    public GridMasterControl()
    {
        this.Grid = new EditableGrid();
    }
}
TheSean
Nice. I like the way you think, sir! Problem with this is it does use up an extra window handle, but it does make for the cleanest code so far.
Mongus Pong