VB.NET: Step-by-Step Guide to Creating a Custom Button Control from Scratch in 2026
Share
In 2026, building a custom button control in VB.NET remains a best practice for achieving consistent UI, improved accessibility, and maintainable theming across Windows Forms and WPF applications. This comprehensive guide walks you through a practical, end-to-end process to design, implement, style, test, and distribute a reusable VB.NET button control that you can reuse across multiple projects.
Why Create a Custom Button Control?
- Consistency: A single control type yields uniform visuals and behavior across forms and modules.
- Extensibility: Add new variants (primary, secondary, danger) via properties, templates, and theming without duplicating code.
- Accessibility: Centralize keyboard activation, focus indicators, and screen reader support.
- Maintainability: Localized logic simplifies updates when UI requirements evolve in 2026 and beyond.
Prerequisites
- Visual Studio 2022 or later with the .NET Desktop development workload installed.
- Familiarity with VB.NET syntax and either Windows Forms or WPF.
- Basic knowledge of custom controls and theming patterns (DependencyProperty in WPF, custom painting in WinForms).
Choosing the Target UI Framework: WinForms vs. WPF
Decide early which framework you’ll target, as the implementation patterns differ. WPF benefits from data binding, templates, and styling through ControlTemplate and DependencyProperty. WinForms relies on overriding painting routines and using ControlStyles for custom rendering. This guide covers both approaches so you can adapt to your project.
Step 1: Create a Shared Class Library for Reusability
Start with a dedicated class library that can be referenced by multiple applications. This enables true reuse and versioning of your custom button.
' VB.NET pseudocode: Create a shared library project
' - For WPF: Create a WPF Custom Control Library (VB)
' - For WinForms: Create a Class Library and a custom control in that library
Step 2: Define the Custom Button Class
Below are two representative implementations: one for WPF using a templated approach, and one for WinForms using custom painting. Pick the approach that matches your target UI framework.
2A. WPF Custom Button (VB.NET)
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Public Class CustomButton
Inherits Button
' Exposed properties for theming
Public Property CornerRadius As Double = 6.0
Public Property ButtonColor As Color = Colors.DodgerBlue
Public Property HoverColor As Color = Colors.CornflowerBlue
Public Property DisabledColor As Color = Colors.Gray
Public Sub New()
MyBase.New()
Me.DefaultStyleKey = GetType(CustomButton)
Me.IsEnabledChanged += Sub(sender, e) OnIsEnabledChanged()
End Sub
Private Sub OnIsEnabledChanged()
' Optional: trigger visual update when enabled/disabled
Me.InvalidateVisual()
End Sub
End Class
For WPF, you’ll wire these properties into a ControlTemplate in Generic.xaml or the consuming app’s resources to style the button based on states like Normal, Hover, Pressed, and Disabled.
2B. WinForms Custom Button (VB.NET)
Imports System.Drawing
Imports System.Windows.Forms
Public Class CustomButton
Inherits Button
Public Property CornerRadius As Integer = 8
Public Property ButtonColor As Color = Color.DodgerBlue
Public Property HoverColor As Color = Color.RoyalBlue
Public Property PressedColor As Color = Color.MidnightBlue
Private Sub New()
' Enable custom painting
SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer, True)
UpdateStyles()
End Sub
Protected Overrides Sub OnPaint(pe As PaintEventArgs)
MyBase.OnPaint(pe)
Dim g = pe.Graphics
Dim rect = New Rectangle(0, 0, Width - 1, Height - 1)
Dim color = If(Me.ClientRectangle.Contains(Cursor.Position), HoverColor, ButtonColor)
If Not Me.Enabled Then color = DisabledColor
Using brush = New SolidBrush(color)
Using path = RoundedRectanglePath(rect, CornerRadius)
g.FillPath(brush, path)
End Using
End Using
' Optional: draw text centered
TextRenderer.DrawText(g, Me.Text, Me.Font, rect, ForeColor, TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter)
End Sub
Private Function RoundedRectanglePath(rect As Rectangle, radius As Integer) As Drawing2D.GraphicsPath
Dim path = New Drawing2D.GraphicsPath()
' Simplified rounded rectangle path creation
path.AddArc(rect.X, rect.Y, radius, radius, 180, 90)
path.AddArc(rect.Right - radius, rect.Y, radius, radius, 270, 90)
path.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90)
path.AddArc(rect.X, rect.Bottom - radius, radius, radius, 90, 90)
path.CloseFigure()
Return path
End Function
End Class
Step 3: Implement Rendering and Styling
Rendering defines how the button looks across states: Normal, Hover, Pressed, Focused, and Disabled. The approach differs by framework.
WPF: Styling with ControlTemplate
<Style TargetType=