
Winforms doesn’t make customising standard controls very easy! This article shows you how to customise menus and toolbars with a fine level of granularity.
For controls such as ContextMenuStrip, MenuStrip and ToolbarStrip you are normally highly limited to the basics when it comes to changing their appearance and normally there’s a lot lacking. For example, with the context menu, you can change the background colour, but not the foreground! I stumbled across this task when trying to implement a “Dark Mode” for an application. Eventually the approach detailed below turned this:
into this:
In this example, I am applying these changes to a ContextMenuStrip. However, I think it should work with other types of toolbars and menus too. It was a bit of a faff, but I finally figured it. You have to use two particular class types to customise the rendering of these controls. A ToolStripProfessionalRenderer and a ProfessionalColorTable Class. You need to insert the two classes below into your code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
Imports System.Drawing Imports System.Windows.Forms Public Class ContextMenuStripRendererDark Inherits ToolStripProfessionalRenderer Public Sub New() MyBase.New(New ProfessionalColorTableDark) End Sub Public MenuBackColor = Constant.BW30 Public MenuForeColor = Constant.BWD0 Public ArrowColor = Constant.BW80 Public SeparatorColor = Constant.BW60 Protected Overrides Sub OnRenderToolStripBackground(e As ToolStripRenderEventArgs) e.Graphics.FillRectangle(New SolidBrush(MenuBackColor), e.AffectedBounds) MyBase.OnRenderToolStripBackground(e) End Sub Protected Overrides Sub OnRenderItemText(e As ToolStripItemTextRenderEventArgs) e.TextColor = MenuForeColor MyBase.OnRenderItemText(e) End Sub Protected Overrides Sub OnRenderArrow(e As ToolStripArrowRenderEventArgs) e.ArrowColor = ArrowColor MyBase.OnRenderArrow(e) End Sub Protected Overrides Sub OnRenderSeparator(e As ToolStripSeparatorRenderEventArgs) Dim forecolorpen As Pen = New Pen(New SolidBrush(SeparatorColor), 1) Dim g As Graphics = e.Graphics Dim bounds As Rectangle = New Rectangle(Point.Empty, e.Item.Size) If bounds.Width >= 4 Then bounds.Inflate(-4, 0) Dim startY As Integer = bounds.Height / 2 g.DrawLine(forecolorpen, bounds.Left, startY, bounds.Right - 1, startY) MyBase.OnRenderSeparator(e) End Sub End Class |
And..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
Imports System.Drawing Imports System.Windows.Forms Public Class ProfessionalColorTableDark Inherits ProfessionalColorTable Dim MenuBackColor = Constant.BW30 Dim MenuBorderColor = Constant.BW80 Dim SelectionColor = Constant.BW40 Dim SeparatorColor = Constant.BW60 Dim CheckPressedColor = Constant.BW20 Public Overrides ReadOnly Property CheckBackground As Color Get Return CheckPressedColor End Get End Property Public Overrides ReadOnly Property CheckPressedBackground As Color Get Return SelectionColor End Get End Property Public Overrides ReadOnly Property CheckSelectedBackground As Color Get Return MenuBackColor End Get End Property Public Overrides ReadOnly Property MenuItemSelected As Color Get Return SelectionColor End Get End Property Public Overrides ReadOnly Property ToolStripDropDownBackground As Color Get Return MenuBackColor End Get End Property Public Overrides ReadOnly Property SeparatorDark As Color Get Return SeparatorColor End Get End Property Public Overrides ReadOnly Property ImageMarginGradientBegin As Color Get Return MenuBackColor End Get End Property Public Overrides ReadOnly Property ImageMarginGradientEnd As Color Get Return MenuBackColor End Get End Property Public Overrides ReadOnly Property ImageMarginGradientMiddle As Color Get Return MenuBackColor End Get End Property Public Overrides ReadOnly Property MenuItemSelectedGradientBegin As Color Get Return SelectionColor End Get End Property Public Overrides ReadOnly Property MenuItemSelectedGradientEnd As Color Get Return SelectionColor End Get End Property Public Overrides ReadOnly Property MenuItemPressedGradientBegin As Color Get Return SelectionColor End Get End Property End Class |
Finally, you need to change a couple of properties on the relevant control. E.g.:
1 2 3 4 5 |
Dim cms As New ContextMenuStrip With cms .RenderMode = ToolStripRenderMode.Professional .Renderer = New ContextMenuStripRendererDark() End With |
You can change the colours to match your requirements. There are other properties and methods that you can override in these rendering classes if needed. Links to a list of these below:
ToolStripProfessionalRenderer | Microsoft Link |
ProfessionalColorTable | Microsoft Link |
Enjoy!
Leave a Reply