Adding border to scrollable component - vb.net

I derived a component from System.Windows.Forms.ScrollableControl and I have problems to add border property. I tried with CreateParams but without success, maybe I miss something?
Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
Get
Dim params As CreateParams = MyBase.CreateParams
params.Style = params.Style Or &H800000 ' Turn on WS_BORDER
Return params
End Get
End Property
'disable scroll bars, this part also disables my border
Protected Overrides Sub DefWndProc(ByRef m As Message)
If m.Msg <> 131 Then
MyBase.DefWndProc(m)
End If
End Sub

Looks like you want to have a border property of true/false:
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim params As CreateParams = MyBase.CreateParams
If _Border Then
params.Style = params.Style Or &H800000 ' Turn on WS_BORDER
End If
Return params
End Get
End Property
Private _Border As Boolean = False
Property Border() As Boolean
Get
Return _Border
End Get
Set(ByVal value As Boolean)
_Border = value
Me.RecreateHandle()
Me.Invalidate()
End Set
End Property
Bob Powell has an article regarding that: Adding a standard border to a control

Ok, solved to have no scrollbars and the nice standard border property together :) Here is the code, in case anyone needs:
Region "Disable scroll bars"
<DllImport("user32.dll")> _
Private Shared Function ShowScrollBar(ByVal hWnd As IntPtr, ByVal wBar As Integer, ByVal bShow As Integer) As Integer
End Function
Protected Overrides Sub DefWndProc(ByRef m As Message)
If m.Msg = 131 Then
ShowScrollBar(m.HWnd, 3, 0)
End If
MyBase.DefWndProc(m)
End Sub
End Region

Related

form with no focus will not move smoothly

I am building a popup keyboard. I'm using sendkeys, so I don't want the form/keyboard to take focus. This code prevents that:
Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.Style = cp.Style Or &H56000000
Return cp
End Get
However, when I try to move the form/keyboard it doesn't move smoothly. It will move, but only after you release the mouse. Is there a way that I can have both, no focus and move smoothly?
I added:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_MOVING Then
Dim r As RECT
r = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(RECT)), RECT)
Me.Location = New Point(r.Left, r.Top)
End If
MyBase.WndProc(m)
End Sub
which then allowed the form to move correctly.
Here's all of the code:
Imports System.Runtime.InteropServices
Private Const WS_CHILD = &H40000000
Private Const WS_EX_NOACTIVATE = &H8000000
Private Const WM_MOVING = &H216
Private Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim p As CreateParams = MyBase.CreateParams
p.Style = p.Style Or WS_CHILD
p.ExStyle = p.ExStyle Or WS_EX_NOACTIVATE
Return p
End Get
End Property
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_MOVING Then
Dim r As RECT
r = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(RECT)), RECT)
Me.Location = New Point(r.Left, r.Top)
End If
MyBase.WndProc(m)
End Sub

custom datagridview column Control will not accept a period (.)

I cannot get a control I found online to accept a period(.). I need to be able to enter numeric values with decimal places. I wanted to use the numericupdown control in a datagridview cell so I can use the up-down arrows for adjusting values.
This control implments the NumericUpDown control as the editing control on a datagridview column. I found it online (don't remember where), and ti was based on a similar custom datagridview column based in a calendar control.
I made a few modifications to it so I could set the maximum, minimum, decimalplaces and imcrement properties.
However, even when decimal places is set to 2 and increment is .1, when I'm typing a value the control will not accept a period.
Below is the code, which includes the classes for the column, cell, and editing control. Please help. I have no clue what the problem is.
Public Class NumericUpDownColumn
Inherits DataGridViewColumn
Public Sub New()
MyBase.New(New NumericUpDownCell())
End Sub
Public Overrides Property CellTemplate() As DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set(ByVal value As DataGridViewCell)
' Ensure that the cell used for the template is a CalendarCell.
If Not (value Is Nothing) AndAlso _
Not value.GetType().IsAssignableFrom(GetType(NumericUpDownCell)) _
Then
Throw New InvalidCastException("Must be a CalendarCell")
End If
MyBase.CellTemplate = value
End Set
End Property
Private _Maximum As Decimal = 100
Private _Minimum As Decimal = 0
Private _Increment As Decimal = 0.1
Private _DecimalPlaces As Integer = 2
Public Property DecimalPlaces() As Integer
Get
Return _DecimalPlaces
End Get
Set(ByVal value As Integer)
If _DecimalPlaces = value Then
Return
End If
_DecimalPlaces = value
End Set
End Property
Public Property Maximum() As Decimal
Get
Return _Maximum
End Get
Set(ByVal value As Decimal)
_Maximum = value
End Set
End Property
_
Public Property Minimum() As Decimal
Get
Return _Minimum
End Get
Set(ByVal value As Decimal)
_Minimum = value
End Set
End Property
_
Public Property Increment() As Decimal
Get
Return _Increment
End Get
Set(ByVal value As Decimal)
_Increment = value
End Set
End Property
End Class
Public Class NumericUpDownCell
Inherits DataGridViewTextBoxCell
Public Sub New()
' Use the short date format.
Me.Style.Format = "N2"
End Sub
Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, _
ByVal initialFormattedValue As Object, _
ByVal dataGridViewCellStyle As DataGridViewCellStyle)
' Set the value of the editing control to the current cell value.
MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, _
dataGridViewCellStyle)
Dim ctl As NumericUpDownEditingControl = _
CType(DataGridView.EditingControl, NumericUpDownEditingControl)
RemoveHandler ctl.Enter, AddressOf Me.OnNumericEnter
AddHandler ctl.Enter, AddressOf Me.OnNumericEnter
ctl.Maximum = CType(Me.DataGridView.Columns(Me.ColumnIndex), NumericUpDownColumn).Maximum
ctl.Minimum = CType(Me.DataGridView.Columns(Me.ColumnIndex), NumericUpDownColumn).Minimum
ctl.Increment = CType(Me.DataGridView.Columns(Me.ColumnIndex), NumericUpDownColumn).Increment
ctl.DecimalPlaces = CType(Me.DataGridView.Columns(Me.ColumnIndex), NumericUpDownColumn).DecimalPlaces
ctl.ThousandsSeparator = True
ctl.Value = CType(Me.Value, Decimal)
End Sub
'''
''' Handle on enter event of numeric
'''
'''
'''
'''
Private Sub OnNumericEnter(ByVal sender As Object, ByVal e As EventArgs)
Dim control As NumericUpDownEditingControl = CType(sender, NumericUpDownEditingControl)
Dim strValue As String = control.Value.ToString("N2")
control.Select(0, strValue.Length)
End Sub
Public Overrides ReadOnly Property EditType() As Type
Get
' Return the type of the editing contol that CalendarCell uses.
Return GetType(NumericUpDownEditingControl)
End Get
End Property
Public Overrides ReadOnly Property ValueType() As Type
Get
' Return the type of the value that CalendarCell contains.
Return GetType(Decimal)
End Get
End Property
Public Overrides ReadOnly Property DefaultNewRowValue() As Object
Get
' Use the current date and time as the default value.
Return 0
End Get
End Property
End Class
Class NumericUpDownEditingControl
Inherits NumericUpDown
Implements IDataGridViewEditingControl
Private dataGridViewControl As DataGridView
Private valueIsChanged As Boolean = False
Private rowIndexNum As Integer
Public Sub New()
End Sub
Public Property EditingControlFormattedValue() As Object _
Implements IDataGridViewEditingControl.EditingControlFormattedValue
Get
Return Me.Value.ToString("N2")
End Get
Set(ByVal value As Object)
If TypeOf value Is Decimal Then
Me.Value = Decimal.Parse(value)
End If
End Set
End Property
_
Public Function GetEditingControlFormattedValue(ByVal context _
As DataGridViewDataErrorContexts) As Object _
Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
Return Me.Value.ToString("N2")
End Function
Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As _
DataGridViewCellStyle) _
Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
Me.Font = dataGridViewCellStyle.Font
Me.ForeColor = dataGridViewCellStyle.ForeColor
Me.BackColor = dataGridViewCellStyle.BackColor
End Sub
Public Property EditingControlRowIndex() As Integer _
Implements IDataGridViewEditingControl.EditingControlRowIndex
Get
Return rowIndexNum
End Get
Set(ByVal value As Integer)
rowIndexNum = value
End Set
End Property
Public Function EditingControlWantsInputKey(ByVal key As Keys, _
ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
Implements IDataGridViewEditingControl.EditingControlWantsInputKey
' Let the DateTimePicker handle the keys listed.
Select Case key And Keys.KeyCode
'Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, _
' Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp
Case Keys.Up, Keys.Down
Return True
Case Else
Return False
End Select
End Function
Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
' No preparation needs to be done.
End Sub
Public ReadOnly Property RepositionEditingControlOnValueChange() _
As Boolean Implements _
IDataGridViewEditingControl.RepositionEditingControlOnValueChange
Get
Return False
End Get
End Property
Public Property EditingControlDataGridView() As DataGridView _
Implements IDataGridViewEditingControl.EditingControlDataGridView
Get
Return dataGridViewControl
End Get
Set(ByVal value As DataGridView)
dataGridViewControl = value
End Set
End Property
Public Property EditingControlValueChanged() As Boolean _
Implements IDataGridViewEditingControl.EditingControlValueChanged
Get
Return valueIsChanged
End Get
Set(ByVal value As Boolean)
valueIsChanged = value
End Set
End Property
Public ReadOnly Property EditingControlCursor() As Cursor _
Implements IDataGridViewEditingControl.EditingPanelCursor
Get
Return MyBase.Cursor
End Get
End Property
Protected Overrides Sub OnValueChanged(ByVal eventargs As EventArgs)
' Notify the DataGridView that the contents of the cell have changed.
valueIsChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnValueChanged(eventargs)
End Sub
End Class
I used an old programmers trick to solve this. I just downloaded the sample code from the post Plutonix referenced and just added the DLL it came with to my project. This work fine and saved me a lot of trouble I wasn't looking for.

Hiding up/down buttons on NumericUpDown control

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?
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.
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

Override datetimepicker vb.net

I would like to overrides the datetimepicker object to remove the texte when the property _clearOnDisabled is true. When _readOnly property is true, I would like to show the text in black not gray.
So I tried with WndProc but I seem that every single object go through my function not only my datetimepicker. I get 100% CPU when I put the WM_PAINT message. I also tried to overrides the OnPaint but its not getting in.
Thx for the help
Imports System.Drawing
Imports System.Windows.Forms
Imports DTP.WindowsMessages
Public Class DTP
Inherits System.Windows.Forms.DateTimePicker
Private _readOnly As Boolean = False
Private _clearOnDisabled As Boolean = True
Private _backColorReadOnly As Color = MyBase.BackColor
Public Sub New()
MyBase.New()
End Sub
Public Overrides Property BackColor() As Color
Get
Return MyBase.BackColor
End Get
Set(ByVal Value As Color)
MyBase.BackColor = Value
If Not _readOnly Then
Me.Invalidate()
End If
End Set
End Property
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case WM_ERASEBKGND
Dim g As Graphics = Graphics.FromHdc(m.WParam)
Dim backBrush As SolidBrush
If _readOnly Then
backBrush = New SolidBrush(_backColorReadOnly)
g.FillRectangle(backBrush, Me.ClientRectangle)
Else
backBrush = New SolidBrush(MyBase.BackColor)
g.FillRectangle(backBrush, Me.ClientRectangle)
End If
g.Dispose()
Case WM_LBUTTONDOWN, WM_KEYDOWN
If Not _readOnly Then
MyBase.WndProc(m)
End If
'Case WM_PAINT ', WM_NCPAINT, WM_DRAWITEM
' If Not _clearOnDisabled Then
' MyBase.WndProc(m)
' End If
Case Else
MyBase.WndProc(m)
End Select
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
If Not _clearOnDisabled Then
MyBase.OnPaint(e)
End If
End Sub
Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaintBackground(pevent)
End Sub
Public Property [ReadOnly]() As Boolean
Get
Return _readOnly
End Get
Set(ByVal Value As Boolean)
_readOnly = Value
Me.Invalidate()
End Set
End Property
Public Property BackColorReadOnly() As Color
Get
Return _backColorReadOnly
End Get
Set(ByVal Value As Color)
_backColorReadOnly = Value
If _readOnly Then
Me.Invalidate()
End If
End Set
End Property
End Class
Don't eat the paint message, but paint after it:
Case WM_PAINT
MyBase.WndProc(m)
If _clearOnDisabled Then
Dim dc As IntPtr = GetWindowDC(Me.Handle)
Using g As Graphics = Graphics.FromHdc(dc)
g.FillRectangle(SystemBrushes.Window, New Rectangle(SystemInformation.Border3DSize.Width, _
SystemInformation.Border3DSize.Height, _
Me.ClientSize.Width - SystemInformation.VerticalScrollBarWidth, _
Me.ClientSize.Height))
End Using
ReleaseDC(Me.Handle, dc)
End If
You can get rid of your OnPaint, OnPaintBackground overrides.

User Control and Binding

I've created a custom control which consists of two radio buttons with their appearance set to "Button". This control is meant to act like two toggle buttons with an "On" toggle button and an "Off" toggle button. I have a public boolean property "isAOn" which is used to set the state of both buttons and I want to be able to bind this property to boolean values. I have imported the component model and set
Now when I add this to a form for a boolean value in one of my classes it doesn't seem to update the boolean value of the class when I change the button pressed.
Advice on how to resolve this issue and constructive criticism on class design is more than welcome.
Thanks!
Here is the code:
Imports System.ComponentModel
''#
<DefaultBindingProperty("isAOn")> _
Public Class ToggleButtons
Private _isAOn As Boolean
Private _aText As String
Private _bText As String
Private _aOnColor As Color
Private _aOffColor As Color
Private _bOnColor As Color
Private _bOffColor As Color
Public Sub New()
''# This call is required by the Windows Form Designer.
InitializeComponent()
''# Add any initialization after the InitializeComponent() call.
aOffColor = Color.LightGreen
aOnColor = Color.DarkGreen
bOffColor = Color.FromArgb(255, 192, 192)
bOnColor = Color.Maroon
isAOn = False
aText = "A"
bText = "B"
End Sub
Private Sub configButtons()
If _isAOn Then
rbA.Checked = True
rbA.BackColor = _aOnColor
rbB.Checked = False
rbB.BackColor = _bOffColor
Else
rbA.Checked = False
rbA.BackColor = _aOffColor
rbB.Checked = True
rbB.BackColor = _bOnColor
End If
rbA.Text = aText
rbB.Text = bText
End Sub
Public Property isAOn() As Boolean
Get
Return _isAOn
End Get
Set(ByVal value As Boolean)
_isAOn = value
configButtons()
End Set
End Property
Private Sub rbOn_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rbA.CheckedChanged
isAOn = rbA.Checked
End Sub
Private Sub rbOff_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rbB.CheckedChanged
isAOn = Not rbB.Checked
End Sub
Public Property aText() As String
Get
Return _aText
End Get
Set(ByVal value As String)
_aText = value
End Set
End Property
Public Property bText() As String
Get
Return _bText
End Get
Set(ByVal value As String)
_bText = value
End Set
End Property
Public Property aOnColor() As Color
Get
Return _aOnColor
End Get
Set(ByVal value As Color)
_aOnColor = value
End Set
End Property
Public Property aOffColor() As Color
Get
Return _aOffColor
End Get
Set(ByVal value As Color)
_aOffColor = value
End Set
End Property
Public Property bOnColor() As Color
Get
Return _bOnColor
End Get
Set(ByVal value As Color)
_bOnColor = value
End Set
End Property
Public Property bOffColor() As Color
Get
Return _bOffColor
End Get
Set(ByVal value As Color)
_bOffColor = value
End Set
End Property
End Class
You need to add an isAOnChanged event and raise it in the property setter.
By the way, properties and methods in .Net should be UpperCamelCased.