NumericUpDown extended control
Please let our ADS show!
This sites offers only FREE software and it's supported by a few advertisement boxes (no intrusive popups).
Please:
- disable your AdBlocker by adding CoolSoft website to whitelist
- give the proper cookie consent
- enable JavaScript for this website
This seconds wait is to let you update your browser configuration...
Ok, I've done the required changes... now show me your content!Introduction
If you have ever written a data-entry application, there's a big chance you used NumericUpDown control. This control is great to provide a field to enter numeric values, with advanced features like up-down buttons and accelerating auto-repeat.
The other side of the coin is that NumericUpDown
is not really mouse-aware. I experienced some bugs and bad behaviors:
- I need to select all the text when it gets focus (see below), but it misses some of the
TextBox
properties, likeSelectedText
,SelectionStart
,SelectionLength
(anAutoSelect
property will be useful). - Some of the standard events are not working properly (see below):
MouseEnter
,MouseLeave
. - Rotating the mouse wheel when the control is focused causes its value to change. A property to change this behavior, like
InterceptArrowsKeys
for up/down keys, will be useful.
That's why I decided to subclass it, fixing these points and adding missing features and properties.
Note: this control has been published on CodeProject.
Missing TextBox properties
I needed some missing TextBox
properties when I was asked to select all the text in the control when it got the focus.
Yes, NumericUpDown
exposes a Select(int Start, int Lenght)
method you can call to select all text. At first try, I attached to the GotFocus
event to call Select(0, x)
but, hey, wait a moment... what should I use for x? It seems that any value is accepted, even if greater than the text length. OK, let's say x=100 and proceed. This works well with the keyboard focus keys (like TAB), but it's completely useless with the mouse: a mouse click raises the GotFocus
event (where I select all the text), but as soon as you release the button, a zero-selection is done, leaving the control with no selection. OK, I thought, let's add a SelectAll
on the MouseUp
event too, but this way, the user cannot perform a partial selection anymore; each time the mouse button is released, all the text is selected. I need to know if a partial selection exists; in a TextBox
, I can test it with SelectionLength > 0
, so I need to access the underlying TextBox
control.
Now comes the tricky part: NumericUpDown
is a composite control, a TextBox
and a button box. Looking inside it through the Reflector, we can find the internal field which holds the textbox part:
Friend upDownEdit As UpDownEdit ' UpDownEdit inherits from TextBox
We'll obtain a reference to this field using the underlying Controls() collection. Note that we should add some safety checks because .NET guys could change things in the future.
''' <summary> ''' object creator ''' </summary> Public Sub New() MyBase.New() ' get a reference to the underlying UpDownButtons field ' Underlying private type is System.Windows.Forms.UpDownBase+UpDownButtons _upDownButtons = MyBase.Controls(0) If _upDownButtons Is Nothing _ OrElse _upDownButtons.GetType().FullName <> "System.Windows.Forms.UpDownBase+UpDownButtons" Then Throw New ArgumentNullException(Me.GetType.FullName & ": Can't a reference to internal UpDown buttons field.") End If ' Get a reference to the underlying TextBox field. ' Underlying private type is System.Windows.Forms.UpDownBase+UpDownButtons _textbox = TryCast(MyBase.Controls(1), TextBox) If _textbox Is Nothing _ OrElse _textbox.GetType().FullName <> "System.Windows.Forms.UpDownBase+UpDownEdit" Then Throw New ArgumentNullException(Me.GetType.FullName & ": Can't get a reference to internal TextBox field.") End If End Sub
Now that we have the underlying TextBox
, it is possible to export some missing properties:
_ _ Public Property SelectionStart() As Integer Get Return _textbox.SelectionStart End Get Set(ByVal value As Integer) _textbox.SelectionStart = value End Set End Property
And finally, we can have a perfectly working mouse management:
' MouseUp will kill the SelectAll made on GotFocus. ' Will restore it, but only if user have not made ' a partial text selection. Protected Overrides Sub OnMouseUp(ByVal mevent As MouseEventArgs) If _autoSelect AndAlso _textbox.SelectionLength = 0 Then _textbox.SelectAll() End If MyBase.OnMouseUp(mevent) End Sub
Mouse events not raised properly
The original MouseEnter
and MouseLeave
events are raised in couples: a MouseEnter
immediately followed by a MouseLeave
. Maybe that's why, to discourage their use, they are marked with a <browsable(false)>
attribute. Since I need the MouseEnter
event to update my StatusBar
caption, I investigated a little on this "bug".
As said above, NumericUpDown
is a composite control (red rectangle in the following picture) containing a TextBox
(left green rectangle) and some other controls:
The "control" area is the one between the red and the green rectangles; when you fly over it with the mouse, you'll receive the MouseEnter
event while between the red and the green, then MouseLeave
when inside the green rectangle. The same happens when you leave.
The better way to raise these events, now that we can access the underlying TextBox
, is to re-raise the MouseEnter
and MouseLeave
events as raised from the TextBox
itself; this is what NumericUpDownEx
does.
MouseWheel management
NumericUpDown
's management of the mouse wheel is, sometimes, really annoying. Suppose you have an application which displays some kind of chart, with a topmost dialog (toolbox) to let the user change some parameters of the graph. In this dialog, the only controls which can keep the focus are NumericUpDown
ones:
After your user puts the focus inside one of them, the mouse wheel is captured by the NumericUpDown
. When the user wheels to, say, scroll the graph, the effect is that the focused field value is changed; this behavior is really annoying.
A fix could be to kill the WM_MOUSEWHEEL
message for the control, but this will kill even "legal" wheelings.
The NumericUpDown
has a property which allows WM_MOUSEWHEEL
messages to pass only if the mouse pointer is over the control, making sure that the user is wheeling to change the control value.
This is done by keeping track of the mouse state in the MouseEnter-MouseLeave
events, then killing WM_MOUSEWHEEL
messages accordingly.
Up-Down buttons visibility
You can hide Up and Down buttons box when the mouse is not over the control.
To achieve this, set the ShowUpDownButtons
property to WhenMouseOver
instead of Always
.
How to use the control
Simply compile sources and include NumericUpDownEx.vb in your project, using the control like you'll do with the standard NumericUpDown
.
You could also directly include its source code into your project, avoiding the deployment of an additional DLL.
v1.5 (28/Mar/2014)
- Removed reflection code, now underlying controls are retrieved with managed code only (thanks to JWhattam for this suggestion).
v1.4 - 2012-12-17
- New option to show up/down buttons when the control has focus (regardless of mouseover), thanks to Fred Kreppert for his suggestion.
v1.3 - 2010-03-15
- Added new property: when set, if Maximum is reached during an increment, Value will restart from Minimum (and vice versa)
(feature suggested by YosiHakel here) - Cleaned up the C# version
v1.2 - 2010-02-10
- Added two new events BeforeValueDecrement and BeforeValueIncrement, as suggested by andrea@gmi.
This will allow to give different increment/decrement depending on current control value - Added a C# version of the control to the ZIP
Download
NumericUpDownEx_1.5_src.zip | |||
Release date | 2014-Mar-28 | Size | 33,494 bytes |
MD5 | c10dc67eea7d4d658e797423e45cf229 | ||
SHA1 | 0af4044c5929025e0e61962b3da0d59b1811ff01 | ||
SHA256 | 27717ff6508ac00ef50cfa7f45f0304fd68407f5ba39fe110a8c89b388adaf02 | ||
Open virus check report |
Navigation
Login
Support me
Click here if you want to support CoolSoft using PayPal
Comments
Suggestions
Thanks for C# code (I was looking for a wrapping solution).
Here some additional suggestions:
1) Double click on up/down to set Maximum/Minimum
2) Support for units. Let's say you are defining a base unit string like 'inch'. And additional units strings with a factor like 'cm' + 1/2.54. The value would always be returned in the base unit. Means if the user enters one of the additional units the value in the text box will be multiplied with the factor and set as value.
cu Martin
Your suggestion sounds good;
Your suggestion sounds good; could you provide a patch?
If yes I'll include it to next version.
You could also throw the same idea on CodeProject...
Sorry no, I was hoping you
Sorry no, I was hoping you could. At least for the double-click. But here is a patch for wrapping which respects the increment.
Thanks for your patch, I'll
Thanks for your patch, I'll add it to next version.
Suggestions: Override Validating event - Correction
Thanks for your suggestion, I
Thanks for your suggestion, I'll add it to next release.
Request
This is a great control!
Do you have in your plan to add same enhancements to the datetimepicker control?
I find it quite uncomfortable.
Maax
No, sorry
No, I'm not.
Anyway you can have a look to these links I found for another project of mine:
Hope you find them useful.