禁用时更改 winform datetimepicker 的字体颜色

Change the font color of a winform datetimepicker when disabled

我正在创建在 windows 表单应用程序中禁用时使用标准字体颜色的自定义控件,但在让 DateTimePicker 工作时遇到困难。

我找到了很多答案,但它们已经有 10 多年的历史了,似乎不再有效。 This 是 2007 年的一个简单答案,但是当我复制它时,它可以在 enabled/disabled 上设置 Font 但不再绘制外围组合框图形。

进行更多挖掘后,我发现了一些更完整的代码来绘制组合框图形,结合第一个简单的答案,我创建了以下 class:

public partial class CustomDatetimePicker : DateTimePicker
{

    public CustomDatetimePicker()
    {
        InitializeComponent();

        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        //Graphics g = this.CreateGraphics();
        Graphics g = pe.Graphics;

        //The dropDownRectangle defines position and size of dropdownbutton block, 
        //the width is fixed to 17 and height to 16. The dropdownbutton is aligned to right
        Rectangle dropDownRectangle = new Rectangle(ClientRectangle.Width - 17, 0, 17, 16);
        Brush bkgBrush;
        Brush txtBrush;
        ComboBoxState visualState;

        //When the control is enabled the brush is set to Backcolor, 
        //otherwise to color stored in _backDisabledColor
        if (this.Enabled)
        {
            bkgBrush = new SolidBrush(SystemColors.Window);
            txtBrush = new SolidBrush(SystemColors.WindowText);
            visualState = ComboBoxState.Normal;
        }
        else
        {
            bkgBrush = new SolidBrush(SystemColors.InactiveBorder);
            txtBrush = new SolidBrush(SystemColors.WindowText);
            visualState = ComboBoxState.Disabled;
        }

        // Painting...in action

        //Filling the background
        g.FillRectangle(bkgBrush, 0, 0, ClientRectangle.Width, ClientRectangle.Height);

        //Drawing the datetime text
        g.DrawString(this.Text, this.Font, txtBrush, 0, 2);

        //Drawing the dropdownbutton using ComboBoxRenderer
        if (ComboBoxRenderer.IsSupported)
        {
            ComboBoxRenderer.DrawDropDownButton(g, dropDownRectangle, visualState);
        }

        g.Dispose();
        bkgBrush.Dispose();
    }
}

但在我的例子中 ComboBoxRenderer 不受支持,因此它不会绘制,而且我没有看到另一种不从头开始构建控件的简单绘制方法。

那么我这样做是否正确?是否有像第一个 link 提供的简单答案,或者提供的代码是否有使用 ComboBoxRenderer 的替代方法?

我也做过类似的事情,但是我觉得没有必要在控件被禁用的时候画下拉按钮,因为无论如何都不能点击。当控件被禁用时,将样式设置为 UserPaint,否则让控件自行绘制。

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    var graphics        = e.Graphics;
    var clientRectangle = ClientRectangle;
    var font            = Font;
    var text            = Text;
    var textSize        = TextRenderer.MeasureText(text, font);
    var textBounds      = DrawingHelper.AlignInRectangle(clientRectangle, textSize, ContentAlignment.MiddleLeft);

    graphics.FillRectangle(new SolidBrush(SystemColors.Control), ClientRectangle);

    ControlPaint.DrawBorder(graphics, clientRectangle, SystemColors.ControlDark, ButtonBorderStyle.Solid);

    TextRenderer.DrawText(graphics, text, font, textBounds, SystemColors.WindowText);
}

protected override void OnEnabledChanged(EventArgs e)
{
    base.OnEnabledChanged(e);

    SetStyle();
}

public void SetStyle()
{
    if (DesignMode)
        return;

    SetStyle(ControlStyles.UserPaint, !Enabled);

    Invalidate();
}

public static class DrawingHelper
{
    public static Rectangle AlignInRectangle(Rectangle outer, Size inner, ContentAlignment alignment)
    {
        int x = 0;
        int y = 0;

        switch (alignment)
        {
            case ContentAlignment.BottomLeft:
            case ContentAlignment.MiddleLeft:
            case ContentAlignment.TopLeft:
                x = outer.X;
                break;

            case ContentAlignment.BottomCenter:
            case ContentAlignment.MiddleCenter:
            case ContentAlignment.TopCenter:
                x = Math.Max(outer.X + ((outer.Width - inner.Width) / 2), outer.Left);
                break;

            case ContentAlignment.BottomRight:
            case ContentAlignment.MiddleRight:
            case ContentAlignment.TopRight:
                x = outer.Right - inner.Width;
                break;
        }

        switch (alignment)
        {
            case ContentAlignment.TopCenter:
            case ContentAlignment.TopLeft:
            case ContentAlignment.TopRight:
                y = outer.Y;
                break;

            case ContentAlignment.MiddleCenter:
            case ContentAlignment.MiddleLeft:
            case ContentAlignment.MiddleRight:
                y = outer.Y + (outer.Height - inner.Height) / 2;
                break;

            case ContentAlignment.BottomCenter:
            case ContentAlignment.BottomRight:
            case ContentAlignment.BottomLeft:
                y = outer.Bottom - inner.Height;
                break;
        }

        return new Rectangle(x, y, Math.Min(inner.Width, outer.Width), Math.Min(inner.Height, outer.Height));
    }
}