开发者

Encapsulating a Windows.Forms.Button

开发者 https://www.devze.com 2022-12-28 12:35 出处:网络
I want to define a special kind of button that only allows two possible labels: \"ON\" and \"OFF\". I decided to inherit from a Windows.Forms.Button to 开发者_运维知识库implement this but now I don\'t

I want to define a special kind of button that only allows two possible labels: "ON" and "OFF". I decided to inherit from a Windows.Forms.Button to 开发者_运维知识库implement this but now I don't know I how should enforce this rule. Should I just override the Text property like this?

public override string Text
{
    set
    {
        throw new InvalidOperationException("Invalid operation on StartStopButton!");
    }
}

The problem I see with this is that I am breaking the contract that all buttons should have. If any code tries something like

foreach (Button button in myForm) {
    button.Text = "123";
}

they will get an Exception if I have any of my special buttons on the form, which is something that isn't expectable. First, because people think of properties just as "public" variables, not methods, second, because they are used to using and setting whatever they want to buttons without having to worry with Exceptions.

Should I instead just make the set property do nothing? That could also lead to awkward results:

myButton.Text = "abc";
MessageBox.Show(abc); //not "abc"!

The general idea from the OO world is to in this kind of cases use Composition instead of inheritance.

public class MySpecialButton : <Some class from System.Windows.Forms that already knows how to draw itself on forms>

    private Button button = new Button(); //I'd just draw this button on this class
                                          //and I'd then only show the fields I consider
                                          //relevant to the outside world.
    ...
}

But to make the Button "live" on a form it must inherit from some special class. I've looked on Control, but it seems to already have the Text property defined. I guess the ideal situation would be to inherit from some kind of class that wouldn't even have the Text property defined, but that'd have position, size, etc properties available. Upper in the hierarchy, after Control, we have Component, but that looks like a really raw class.

Any clue about how to achieve this? I know this was a long post :(

Thanks


Have you considered using Control in the way you described but not using the Text property of the Control to set the Text property of the Button?

Lots of Windows Controls have Text properties that aren't used anywhere.


You could hide the Text property from the designer, and then add a new property which takes a simple enumeration with only two values:

public enum MyButtonLabelValue
{
    On,
    Off
}

public class MyButton : Button
{
    [Browsable(false)]
    public override string Text
    {
        get
        {
            return base.Text;
        }
        set
        {
            // either do nothing or only accept "On" and "Off". I know you're concerned about violating the 
            // contract, but that would be preferrable to not having a public .Text property at all
        }
    }


    public MyButtonLabelValue LabelValue 
    {
        get
        {
            return Text == "On" ? MyButtonLabelValue.On : MyButtonLabelValue.Off;
        }
        set
        {
            base.Text = value == MyButtonLabelValue.On ? "On" : "Off";
        }
    }
}


EDIT : I've added the actual code for the question originator didn't quite understand my point. The "New button code"

namespace WindowsFormsApplication1
{
    public partial class Component1 : Component
    {
        public Component1()
        {
            InitializeComponent();
        }

        public Component1(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }
        bool bIsOn = true;
        public bool On
        {
            set 
         {
         bIsOn=value;

         if (bIsOn)
             button1.Text = "ON";
         else 
             button1.Text = "OFF";

         button1.Invalidate(); //force redrawing
        }

        }
        public void AddToForm(System.Windows.Forms.Form form)
        {
            form.Controls.Add(this.button1);
        }
    }
}

The main Form code : 

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Component1 onOffButton = new Component1();

            onOffButton.On = true;

            onOffButton.AddToForm(this);




        }
    }
}

Encapsulating a Windows.Forms.Button

You must not use inheritance here because it would make no sense from OOP principles POV.

Limiting Text property input violates the original interface. Instead, define your own interface and implementation by use of composition, and have it set values by simple boolean test, like this:

class OnOffButton : I_OnOffButton
{
     Button regularButton;
     bool bIsOn = true;
     public bool On
     {
      set 
         {
         bIsOn=value;

         bIsOn?(regularButton.Text = "ON"):(regularButton.Text = "OFF")

         regularButton.Invalidate(); //force redrawing
        }
     }
...

}

Hope this helps!

0

精彩评论

暂无评论...
验证码 换一张
取 消