I suggest to use a Custom Control derived from NumericUpDown, so you can handle internally the value changed events that are generated by different possible actions: click the Up/Down Buttons, spin the MouseWheel, enter a number manually, data bindings etc.
The OnValueChanged method override has the last word: if a value submitted doesn't meet the criteria (being a power of two in the specified range), the number is changed to the nearest (higher) valid value.
The OnMouseWheel override just calls the corresponding method based on the positive or negative value of the Delta.
► Requires Option Infer On
or small changes
Imports System.ComponentModel
Imports System.Windows.Forms
<DesignerCategory("Code")>
Public Class NumericUpDownPow2
Inherits NumericUpDown
Public Sub New()
Me.Maximum = 64
Me.Minimum = 1
End Sub
Public Overrides Sub UpButton()
Value = Math.Min(Value * 2, Maximum)
End Sub
Public Overrides Sub DownButton()
Value = Math.Max((Value / 2), Minimum)
End Sub
Protected Overrides Sub OnMouseWheel(e As MouseEventArgs)
Call If(e.Delta > 0, Sub() UpButton(), Sub() DownButton())
DirectCast(e, HandledMouseEventArgs).Handled = True
MyBase.OnMouseWheel(e)
End Sub
Protected Overrides Sub OnValueChanged(e As EventArgs)
Dim nearest = CDec(Math.Round(2 ^ Math.Ceiling(Math.Log(Value, 2))))
Value = Math.Max(Math.Min(nearest, Maximum), Minimum)
MyBase.OnValueChanged(e)
End Sub
End Class