2

我最近需要编写一个版本的 Windows NumericUpDown 控件,它可以突出显示一个值是否是强制性的。它需要通过更改控件的背景颜色来做到这一点。我认为这很简单,但在尝试这样做时,我发现它有一个奇怪的副作用,即没有完全绘制所有控件。

使用下面的代码,我看到了:

当我在 Windows 窗体上放置一个控件并更改 BackColor 属性(即更改为 Blue)时,整个控件的数字部分都会改变颜色。如果,或者,我改变了我的“IsMandatory”属性,并不是所有的背景颜色都改变了(它留下了一个边框)。因此,如果我将 BackColor 更改为 Blue,然后将 IsMandatory 设置为 True,我会得到一个带有蓝色边框的 LightBlue 控件(强制颜色) 。

我不明白为什么会这样,因为它们都使用相同的代码。

想法或解释非常受欢迎。

   public partial class MyNumericUpDown : NumericUpDown
   {
      private Boolean _isMandatory = false;
      private Color _mandatoryBackColor = Color.LightBlue;
      private Color _backColor = Color.FromKnownColor(KnownColor.Window);

      [DefaultValue(typeof(Color), "Window"), Description("Overridden property")]
      override public Color BackColor
      {
         get { return _backColor; }
         set
         {
            _backColor = value;
            MyResetColors();
         }
      }

      [DefaultValue(typeof(Color), "LightBlue"), Category("Appearance")]
      public Color MandatoryBackColor
      {
         get {return _mandatoryBackColor;}
         set 
         {
            _mandatoryBackColor = value;
            MyResetColors();
         }
      }

      [DefaultValue(false), Category("Behavior")]
      public Boolean IsMandatory
      {
         get { return _isMandatory; }
         set
         {
            _isMandatory = value;
            MyResetColors();
         }
      }

      private void MyResetColors()
      {
         base.BackColor = (this.IsMandatory ? this.MandatoryBackColor : this.BackColor);
      }
   }

这是它的样子:

4

3 回答 3

2

有趣的问题,它演示了压倒一切的虚拟成员如何产生意想不到的副作用。核心问题是您的 BackColor 属性获取器,它始终返回 _backColor 属性值,即使您使用 IsMandatory 强制它为不同的值。Winforms 在需要绘制控件背景时也会使用该属性 getter。因此,您将返回 Blue,这解释了您在屏幕截图中看到蓝色的原因。

但奇怪的是,它仍然适用于控件的文本部分。那是因为 NumericUpdown 由多个控件组成。您有一个 ContainerControl 设置外部边界并且是基类,您正在覆盖它的 BackColor 属性。但其中还有另外两个控件,一个显示文本的 TextBox 和一个显示向上/向下按钮的控件。您的 BackColor 属性覆盖不会覆盖它们的 BackColor 属性。因此,文本框部分将使用您分配给 Base.BackColor 的颜色进行绘制

要解决这个问题,您将不得不停止对 BackColor 撒谎。有了额外的约束,您需要确保这在设计时仍然有效,以便实际的 BackColor 被序列化,而不是 MandatoryColor:

[DefaultValue(typeof(Color), "Window"), Description("Overridden property")]
override public Color BackColor {
    get {
        return base.BackColor;
    }
    set {
        _backColor = value;
        MyResetColors();
    }
}

private void MyResetColors() {
    base.BackColor = this.IsMandatory && !DesignMode ? this.MandatoryBackColor : _backColor;
}
于 2012-05-17T10:34:40.797 回答
0

Windows 在禁用时无法正确/完全重新绘制 NumericUpDown 控件。

请参阅此帖子: NumericUpDown 禁用元素的背景颜色更改

显示后启用/禁用控件是一种解决方法。

于 2017-11-15T13:23:38.393 回答
0

上述方法对我不起作用。我的解决方法是:

    private void smartRefresh()
    {
        if (oldBackColor != BackColor) {
            oldBackColor = BackColor;
            Hide();
            Application.DoEvents();
            Show();
            Application.DoEvents();
        }
    }

有一个私人成员 oldBackColor。

现在它总是正确显示但不闪烁。

附录:我认为控件的某些部分根本没有被绘制(我认为这是一个错误),因为它周围的“错误绘制”的 bos 没有统一着色,有时可以看到以前存在的窗口痕迹。

于 2015-12-04T19:46:32.117 回答