封装Windows.Forms.Button

时间:2010-04-23 19:29:50

标签: c# .net winforms oop

我想定义一种特殊的按钮,它只允许两种可能的标签:“ON”和“OFF”。我决定继承Windows.Forms.Button来实现这个,但现在我不知道我应该如何强制执行这条规则。我应该像这样覆盖Text属性吗?

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

我看到的问题是我违反了所有按钮应该具有的合同。如果任何代码尝试类似

foreach (Button button in myForm) {
    button.Text = "123";
}
如果我在表单上有任何特殊按钮,那么他们会得到一个例外,这是不可预期的。首先,因为人们将属性视为“公共”变量,而不是方法,其次,因为他们习惯于使用和设置他们想要的任何按钮,而不必担心例外。

我应该只是让set属性什么都不做?这也可能导致尴尬的结果:

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

OO世界的一般想法是在这种情况下使用Composition而不是继承。

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.
    ...
}

但是为了使Button“生活”在一个表单上,它必须从一些特殊的类继承。我看过Control,但似乎已经定义了Text属性。我想理想的情况是继承某些甚至没有定义Text属性的类,但是它有可用的位置,大小等属性。层次结构中的上层,在Control之后,我们有Component,但它看起来像一个非常原始的类。

有关如何实现这一目标的任何线索?我知道这是一篇很长的帖子:(

由于

3 个答案:

答案 0 :(得分:2)

您是否考虑过按照描述的方式使用Control但不使用Control的Text属性来设置Button的Text属性?

许多Windows控件具有不在任何地方使用的Text属性。

答案 1 :(得分:1)

您可以从设计器中隐藏Text属性,然后添加一个新属性,该属性只使用两个值进行简单枚举:

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";
        }
    }
}

答案 2 :(得分:1)

编辑:我已经添加了问题发起人的实际代码并不太明白我的观点。 “新按钮代码”

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);




        }
    }
}

alt text

你不能在这里使用继承,因为从OOP原则POV中没有任何意义。

限制Text属性输入违反原始界面。 相反,通过使用组合定义自己的接口和实现,并通过简单的布尔测试设置值,如下所示:

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
        }
     }
...

}

希望这有帮助!