drvolcano
drvolcano

Reputation: 110

extending a class that already inherits another class

I am inheriting some System.Windows.Forms-Control (about 10 pieces). Each of them gets some custom extensions, but most of the extension will be the same for each control.

Actually I have to code the same functionality separate for each of them. This is a lot of copy+paste and difficult to maintain.

class MyButton : Button
{
    //this is only in MyButton
    public int ButtonProperty { get; set; }

    public object Property1 { get; set; }
    public object Property2 { get; set; }

    public void MakeInvisible()
    {
        this.Visible = false;
    }
}

class MyLabel : Label
{
    //this is only in MyLabel
    public bool LabelProperty { get; set; }

    //same propertys and methods as in MyButton
    public object Property1 { get; set; }//copy+paste
    public object Property2 { get; set; }//copy+paste

    public void MakeInvisible()//copy+paste
    {
        this.Visible = false;
    }
}

What I am searching for is a way to extend all of the derived classes like you can do with an interface or extension method. But I also want to have properties and access the base class (Control)

This is what I am dreaming about:

class MyButton : Button, MyExtension
{   
    //this is only in MyButton
    public int ButtonProperty { get; set; }
}

class MyLabel : Label, MyExtension
{
    //this is only in MyLabel
    public bool LabelProperty { get; set; }
}

//Extension for all classes inherited from Control
class MyExtension : Control
{
    public object Property1 { get; set; }
    public object Property2 { get; set; }

    public void MakeInvisible()
    {
        this.Visible = false;
    }
}

Upvotes: 3

Views: 1993

Answers (5)

InBetween
InBetween

Reputation: 32780

If you need to leverage protected methods and properties of the extended controls then you are out of luck, there is no way to acheive what you want without extensive copy and paste.

If you only need access to public methods and properties, then how about something along the following lines:

public interface IControlExtension
{
    Foo MyProperty { get; set; } 
    Blah MyMethod();
}

public abstract class ControlExtension: IControlExtension
{
     private Control owner;

     private ControlExtension(Control owner)
     {
         Debug.Assert(owner != null);
         this.owner = owner;
     }

     public static IControlExtension GetControlExtension(Control c)
     {
          if (c is Button ||
              c is Label)
          {
              return new SimpleControlExtension(c);
          }

          if (c is Panel || ...
          {
              return new ContainerControlExtension(c);
          }  
     }

     public abstract Foo MyProperty { get; set; }
     public abstract Blah MyMethod();

     private class SimpleControlExtension: ControlExtension
     {
          public override Foo MyProperty { .... }
          public override Blah MyMethod { .... 
     }

     private class ContainerControlExtension: ControlExtension
     {
          public override Foo MyProperty { .... }
          public override Blah MyMethod { .... }
     }
}

Now, in all your extended controls, the copy and paste code is minimum:

public class MyButton : Button
{   
    public MyButton()
    {
        ....
        var controlExtension = ControlExtension.GetControlExtension(this);
    }

    public IControlExtension { get { return controlExtension; } }
}

Upvotes: 0

ASh
ASh

Reputation: 35720

idea:

  1. create a new type for common properties

  2. give each control a property of that type

implementation:

// TypeConverter required for PropertyGrid in design mode
// found here: http://stackoverflow.com/a/6107953/1506454
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MyExtension
{
    // need reference to control to work with in methods
    private Control _c;
    public MyExtension(Control c)
    {
        _c = c;
    }

    // can be inhereted for different controls, if necessary

    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public void MakeInvisible()
    {
        _c.Visible = false;
    }
}
// common interface of extended controls
public interface IExtended
{
    MyExtension Extra { get; }
}
// MyButton implements extended interface
public class MyButton : Button, IExtended
{
    public MyButton()
    {
        // create extended properties for button
        Extra = new MyExtension(this);
    }

    // for designer serialization support
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public MyExtension Extra { get; private set; }

    //this is only in MyButton
    public int ButtonProperty { get; set; }
}
// common extension methods
public static class MyControlHelper
{
    public static void MakeInvisible<TControl>(this TControl control) where TControl : Control, IExtended
    {
        control.Extra.MakeInvisible();
    }

    public static void Rename<TControl>(this TControl control) where TControl : Control, IExtended
    {
        control.Text = control.Extra.Property1;
    }
}

Upvotes: 2

juharr
juharr

Reputation: 32296

Instead of inheriting from the Button and Label you could use composition.

class MyExtension
{
    protected Control control;

    public MyExtension(Control control)
    {
        this.control = control;
    }

    public object Property1 { get; set; }
    public object Property2 { get; set; }
    public void MakeInvisible()
    {
        this.control.Visible = false;
    }
}

class MyButton : MyExtension
{
    public MyButton(Button button):base(button){}
    public int ButtonProperty { get; set; }
}

class MyLabel : Label
{
    public MyButton(Label label):base(label){}
    public bool LabelProperty { get; set; }
}

You could even make MyExtension abstract if you don't want any instances of it created. The main difference here is that you'll have to create a Button or Label to pass in and you might want to expose them as properties of your MyButton and MyLabel so you can get at their properties.

Upvotes: 0

Hamid Pourjam
Hamid Pourjam

Reputation: 20764

You can use extension methods for this purpose

public static class ControlHelper
{
    public static void MakeInvisible(this Control c)
    {
        c.Visible = false;
    }
}

and use it like this

var mb = new MyButton();
mb.MakeInvisible();

var ml = new MyLabel();
ml.MakeInvisible();

By using this approach you can generate extension methods for base classes and use it in derived classes.

Upvotes: 0

Vnuuk
Vnuuk

Reputation: 6537

C# doesn't support multi inheritance. You should try something like this - MyButton : MyExtension; and MyExtension : Button. In this case you will extend MyButton class with MyExtension and Button classes.

Upvotes: 0

Related Questions