3

I am very new to C#, and have a question. I have been able to change the border colors of buttons and such by changing their FlatStyle to "Flat". With the NumericUpDown, I can't change the FlatStyle. I would like to still be able to use the up and down arrows, so just using something else to cover the edges will not work. Here is a simplified version of what I'm doing in my code:

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

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

        private void button1_Click(object sender, EventArgs e)
        {
            BackColor = Color.Black;
            numericUpDown1.BackColor = Color.Red;
        }
    }
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • see this link : https://stackoverflow.com/questions/14725328/draw-border-for-numericupdown – Meysam Asadi Jan 25 '21 at 02:29
  • Just as a side note, this control raises paint event and if for any reason someone wants to achieve the same behavior without inheritance they can handle the Paint event and draw the border; however as a general solution and a reusable one, a derived control makes more sense. – Reza Aghaei Jan 25 '21 at 13:15

2 Answers2

5

You can derive from NumericUpDown, add a BorderColor property, override OnPaint and draw border based on the border color.

using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
public class MyNumericUpDown : NumericUpDown
{
    private Color borderColor = Color.Blue;
    [DefaultValue(typeof(Color), "0,0,255")]
    public Color BorderColor
    {
        get { return borderColor; }
        set
        {
            if (borderColor != value)
            {
                borderColor = value;
                Invalidate();
            }
        }
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        if (BorderStyle != BorderStyle.None)
        {
            using (var pen = new Pen(BorderColor, 1))
                e.Graphics.DrawRectangle(pen,
                    ClientRectangle.Left, ClientRectangle.Top,
                    ClientRectangle.Width - 1, ClientRectangle.Height - 1);
        }
    }
}

enter image description here

Note: Just as a side note, this control raises paint event and if for any reason someone wants to achieve the same behavior without inheritance they can handle the Paint event and draw the border; however as a general solution and a reusable one, a derived control makes more sense.

private void numericUpDown_Paint(object sender, PaintEventArgs e)
{
    var c = (NumericUpDown)sender;
    ControlPaint.DrawBorder(e.Graphics, c.ClientRectangle,
        Color.Red, ButtonBorderStyle.Solid);
    var r = new Rectangle(1, 1, c.Width - 2, c.Height - 2);
    e.Graphics.SetClip(r);
}

FlatNumericUpDown

I've created a FlatNumericUpDown which supports BorderColor and ButtonHighlightColor. You can download or clone it:

enter image description here

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • @RezeAghaei I tried to do the first method you used, and VS 2019 gave me the error "CS0119 BorderStyle' is a type, which is not valid in the given context". The second method you gave under the note did work though. I think that I should have been more clear in what I wanted because the color of the thin border did change, which is part of what I wanted. I also wanted to know if I could change the color of those little buttons with the arrows on them too? – fauxvelocity Jan 25 '21 at 19:00
  • Both methods are tested and work properly. Probably you are missing something. – Reza Aghaei Jan 26 '21 at 05:06
  • I've also created a FlatNumericUpDown repository. You can start creating your own FlatNumericUpDown based on that. – Reza Aghaei Jan 26 '21 at 05:15
  • Sine you are interested to flat control, you may also like [Change TextBox BorderColor](https://stackoverflow.com/a/39420512/3110834) and [Change ComboBox BorderColor](https://stackoverflow.com/a/34886006/3110834) – Reza Aghaei Jan 26 '21 at 05:59
  • You may also be interested in [FlatDateTimePicker](https://stackoverflow.com/a/66092509/3110834). – Reza Aghaei Feb 08 '21 at 14:38
2

A Custom Control version that overrides WndProc to paint the NumericUpDown (but it can be applied to many other controls) border using the standard ControlPaint rendering features.

This allows to paint a border without much effort (actually, none :) and have multiple styles available out of the box.

The BorderStyle property is shadowed, to return the extended ButtonBorderStyle values, which includes, e.g., Dotted and Dashed style besides the default Solid.

A public BorderColor Property is added to the class, it will of course appear in the PropertyGrid; it allows to change the color of the Border.
It defaults to Color.DarkGray, which is similar to SystemColors.ControlDark.
You can use the same Attribute style used by Reza Aghaei to specify the RGB value instead of "DarkGray", if you want to be precise.


Add this class to the Project, build the Project, find the Custom Control in the ToolBox and drop it on the Form as usual (in case you don't know what to do with it :)

► Note that you can use this same technique to many other standard Controls (including the TextBox Control, which usually doesn't raise Paint events) and to all of your own designed Custom Controls / Components.

This is what it looks like:

NumericUpdown Custom Border Styles Custom NumericUpdown PropertyGrid


using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

[DesignerCategory("Code"), ToolboxItem(true)]
public class NumericUpDownEx : NumericUpDown
{
    private const int WM_PAINT = 0x000F;
    private ButtonBorderStyle m_BorderStyle = ButtonBorderStyle.Solid;
    private Color m_BorderColor = Color.DarkGray;

    public NumericUpDownEx() { }

    public new ButtonBorderStyle BorderStyle {
        get => m_BorderStyle;
        set {
            if (m_BorderStyle != value) {
                m_BorderStyle = value;
                Invalidate();
            }
        }
    }

    [DefaultValue(typeof(Color), "DarkGray")]
    public Color BorderColor {
        get => m_BorderColor;
        set {
            if (m_BorderColor != value) {
                m_BorderColor = value;
                Invalidate();
            }
        }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        switch (m.Msg) {
            case WM_PAINT:
                if (IsHandleCreated) {
                    using (var g = Graphics.FromHwndInternal(this.Handle)) {
                        ControlPaint.DrawBorder(g, ClientRectangle, m_BorderColor, m_BorderStyle);
                    }
                    m.Result = IntPtr.Zero;
                }
                break;
        }
    }

}
Jimi
  • 29,621
  • 8
  • 43
  • 61