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:

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