Reputation: 4655
I am trying to subclass NumericUpDown in several ways to get better functionality and appearance.
Since NUD is construct of two controls I would like to hide up/down buttons in cases where property "Increment" is set to 0.
This code is in subclass:
Protected Overrides Sub OnTextBoxResize(ByVal source As Object, ByVal e As System.EventArgs)
Controls(0).Hide()
End Sub
... and it work OK. But in that function I cannot check a value of Increment property like this:
Protected Overrides Sub OnTextBoxResize(ByVal source As Object, ByVal e As System.EventArgs)
If Me.Increment = 0 Then
Controls(0).Hide()
End if
End Sub
In scope of this function Me is not reachable. I am also try with using local variables but can't find which event is fired before OnTextBoxResize to read value of Increment property.
What to do in such case to get desired functionality?
Upvotes: 4
Views: 6588
Reputation: 81610
This seems to work fairly well. It Shadows the Increment property in order to set the visibility of the spinner controls when the Increment value is being changed. There is an underlying private method the base control calls called PositionControls
which you cannot stop — that method could create some flicker, but on my test, it didn't.
Public Class MyNumBox
Inherits NumericUpDown
Shadows Property Increment As Decimal
Get
Return MyBase.Increment
End Get
Set(value As Decimal)
MyBase.Increment = value
OnTextBoxResize(Me, EventArgs.Empty)
End Set
End Property
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
OnTextBoxResize(Me, EventArgs.Empty)
End Sub
Protected Overrides Sub OnTextBoxResize(source As Object, e As EventArgs)
If Me.IsHandleCreated Then
Me.Height = Me.PreferredHeight
Me.Controls(0).Visible = (MyBase.Increment > 0)
Dim borderWidth As Integer = 0
If Me.BorderStyle > BorderStyle.None Then
borderWidth = SystemInformation.Border3DSize.Width
End If
Dim textWidth As Integer
If Me.Increment = 0 Then
textWidth = Me.ClientSize.Width - (borderWidth * 2)
Else
textWidth = Me.ClientSize.Width - Me.Controls(0).Width - (borderWidth * 2)
End If
If Me.UpDownAlign = LeftRightAlignment.Left Then
If Me.Increment = 0 Then
Me.Controls(1).SetBounds(borderWidth, borderWidth, _
textWidth, Me.Controls(1).Height)
Else
Me.Controls(1).SetBounds(borderWidth + Me.Controls(0).Width, _
Me.Controls(1).Top, textWidth, Me.Controls(1).Height)
End If
Else
Me.Controls(1).SetBounds(borderWidth, Me.Controls(1).Top, _
textWidth, Me.Controls(1).Height)
End If
Me.Refresh()
End If
End Sub
End Class
In the OnTextBoxResize override, I am re-positioning the controls into their proper place, and this version does account for the UpDownAlign property.
Upvotes: 4
Reputation: 39122
If you can, read this thread over at EE where I answered a similar question. It resizes the edit portion so that the control is redrawn correctly when the buttons have been hidden and the control is resized. *Otherwise the portion of the control where the buttons used to be leaves ghosts behind.
One solution to your specific problem is to wait for the VisibleChanged() event and check the Increment() property from there. Here is a conversion of my previous answer with some minor changes:
Public Class NoArrowNumericUpDown
Inherits NumericUpDown
Private itb As InnerTextBox = Nothing
Protected Overrides Sub OnVisibleChanged(e As System.EventArgs)
If Me.Visible Then
If Me.Increment = 0 AndAlso IsNothing(itb) Then
Dim ctl As Control = Me.Controls(0) ' get the spinners
Me.Controls.Remove(ctl) ' remove the spinners
ctl = Me.Controls(0) ' get the edit control
itb = New InnerTextBox(Me, ctl)
End If
End If
MyBase.OnVisibleChanged(e)
End Sub
Public Class InnerTextBox
Inherits NativeWindow
Private parentControl As Control = Nothing
Const WM_WINDOWPOSCHANGING As Integer = &H46
Public Sub New(parentControl As Control, InnerTextBox As Control)
Me.parentControl = parentControl
Me.AssignHandle(InnerTextBox.Handle)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case WM_WINDOWPOSCHANGING
Dim wp As WindowPos = CType(System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(WindowPos)), WindowPos)
If Me.parentControl IsNot Nothing Then
wp.cx = Me.parentControl.ClientSize.Width - 2 * wp.x
wp.cy = Me.parentControl.ClientSize.Height
System.Runtime.InteropServices.Marshal.StructureToPtr(wp, m.LParam, True)
End If
Exit Select
End Select
MyBase.WndProc(m)
End Sub
Public Structure WindowPos
Public hwnd As IntPtr
Public hwndInsertAfter As IntPtr
Public x As Integer
Public y As Integer
Public cx As Integer
Public cy As Integer
Public flags As UInteger
End Structure
End Class
End Class
EDIT: You could just enclose your code in a Try/Catch block?
Public Class NoArrowNumericUpDown
Inherits NumericUpDown
Protected Overrides Sub OnTextBoxResize(ByVal source As Object, ByVal e As System.EventArgs)
Try
If Me.Increment = 0 Then
Controls(0).Hide()
End If
Catch ex As Exception
End Try
End Sub
End Class
Upvotes: 1