VB.NET: Step-by-Step Guide to Creating a Custom Button Control from Scratch in 2026

VB.NET: Step-by-Step Guide to Creating a Custom Button Control from Scratch in 2026

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=
Back to blog

Leave a comment

Please note, comments need to be approved before they are published.