Custom Panel Controls blinking - vb.net

I've developed a program that inserts an array of Panel-like controls into another Panel control, the code is as follows:
Dim ModSe As Bitmap = Nothing
ModSe = My.Resources.example
Dim pbdoors As New Panel With {
.Width = 100,
.Height = 200,
.Top = 10,
.Left = 10,
.BorderStyle = BorderStyle.FixedSingle,
.BackgroundImage = ModSe,
.BackgroundImageLayout = ImageLayout.Stretch,
.ContextMenuStrip = CntxtMnuStrpUnit,
.Name = ("Test")
}
But when I see the arrangement of Panel controls already inserted, when I step over a control type Tab, they start to flash as if it were a strobe light. In this case, for my Form, I went to the "DoubleBuffered" property and set it to True, but it keeps flashing.
Add the following without any results.
Public Class FlickerPanel
Inherits System.Windows.Forms.Panel
Public Sub New()
MyBase.New()
Me.SetStyle(ControlStyles.Opaque, True)
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.ResizeRedraw, True)
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.EnableNotifyMessage, True)
End Sub
Protected Overrides Sub OnNotifyMessage(ByVal m As Message)
If (m.Msg <> &H14) Then
MyBase.OnNotifyMessage(m)
End If
End Sub
End Class
Protected Overloads Overrides ReadOnly Property CreateParams() As CreateParams
Get
'Dim cp As CreateParams = MyBase.CreateParams
'cp.ExStyle = cp.ExStyle Or 33554432
'Return cp
Dim cp As CreateParams = MyBase.CreateParams
Dim OSVer As Version = System.Environment.OSVersion.Version()
Select Case OSVer.Major
Case Is <= 5
Case 5
If OSVer.Minor > 0 Then
cp.ExStyle = cp.ExStyle Or &H2000000
End If
Case Is > 5
cp.ExStyle = cp.ExStyle Or &H2000000
Case Else
End Select
Return cp
End Get
End Property
Please, how can I eliminate this flicker?

Related

Find control by text and assign custom property with Ctype or item is control in dictionary

I have a EmailTextbox like this:
Imports System.ComponentModel
Public Class EmailTextBox
Inherits TextBox
Private _error As String = ""
Public Sub New()
''
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
Dim brush As New SolidBrush(Me.ForeColor)
e.Graphics.DrawString(Me.Text, Me.Font, brush, 0, 0)
End Sub
Protected Overrides Sub OnValidating(e As CancelEventArgs)
MyBase.OnValidating(e)
Dim isValidEmail As Boolean = ValidatedEmail(Me.Text)
Dim _emailNotValid As String = Global.WindowsApp1.My.Resources.MessageResource.EmailNotValid
Dim _errorBackColor As String = Global.WindowsApp1.My.Resources.MessageResource.ErrorBackColor
e.Cancel = Not isValidEmail Or Me.ValidationError <> ""
'
If Me.ValidationError <> "" Then
_emailNotValid = Me.ValidationError
End If
'
If Not isValidEmail Then
errProvider.SetError(Me, _emailNotValid)
Me.BackColor = ColorTranslator.FromHtml(_errorBackColor)
Else
errProvider.SetError(Me, "")
Me.BackColor = Color.White
End If
End Sub
' custom property for database validation
Public Property ValidationError() As String
Get
Return _error
End Get
Set(ByVal Value As String)
_error = Value
End Set
End Property
End Class
I drag it into form and set name is txtEmail. How do i set ValidationError prop in two cases like this:
Case 1:
CType(Me.Controls("txtEmail"), TextBox).ValidationError = 456
Case 2:
Private Items As New Dictionary(Of String, Control) From {
{"txtEmail", txtEmail}
}
Items("txtEmail").ValidationError = 456
or even shorter:
Me.Controls("txtEmail").ValidationError = 456
Thanks for your answer.
These are some options for achieving what you're looking for.
Private Sub SetValidator()
'if you know that there is only one
Dim myCtrl As EmailTextBox = Me.Controls.OfType(Of EmailTextBox).First
myCtrl.ValidationError = 457
'if you want to find by name
DirectCast(Me.Controls.Find("txtEmail", True)(0), EmailTextBox).ValidationError = 456
End Sub

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

Transparent App Bar Winforms

This will have a lot of code - my apologies but it's necessary to create a working sample.
I am creating an App Bar (top or left) for my application, and I cannot get transparency to work. While I am able to get the form background transparent as a form using:
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
before InitializeComponent(), and then BackColor = Color.Transparent, the App Bar background appears to be "Control." If I then set
Me.Opacity = .75
I receive a WndProc error "The parameter is incorrect."
If I then try to do something like
Me.BackColor = Color.FromArgb(25,0,0,0)
I get (basically) the same "control color" look as I do with a Transparent background.
If I try:
Me.Color = Color.Black
Me.TransparencyKey = Color.Black
I receive a similar error to the Opacity error above (a wndproc 'parameter is incorrect').
Searching has not led me anywhere useful, but I know this must be possible - the Windows taskbar is semi-transparent. I understand that they aren't exactly the same, but there must be some way to accomplish this.
In order to get this working, you should need to simply paste the below into a new Winforms app. I wrote custom auto-hide code, but am not including it to keep this as short as possible. It also won't have a way to close it unless you add a context menu, etc - but probably just stop it for simplicity.
Again, my apologies for the long code, but all is required in order to get this working:
Public Sub New()
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
InitializeComponent()
AddHandler Me.Load, AddressOf Me_Load
AddHandler Me.FormClosing, AddressOf Me_Closing
Me.FormBorderStyle = FormBorderStyle.FixedToolWindow
Me.ShowInTaskbar = False
Me.AllowTransparency = True
'Me.BackColor = Color.FromArgb(10, Color.Black)
'Me.BackColor = Color.Black
'Me.TransparencyKey = Color.Black
'Me.BackColor = Color.Transparent
'Me.Opacity = 0.5
End Sub
Private Sub Me_Load(sender As Object, e As EventArgs)
RegisterBar()
End Sub
Private Sub Me_Closing(sender As Object, e As FormClosingEventArgs)
RegisterBar()
End Sub
<StructLayout(LayoutKind.Sequential)>
Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
End Structure
<StructLayout(LayoutKind.Sequential)>
Structure APPBARDATA
Public cbSize As Integer
Public hWnd As IntPtr
Public uCallbackMessage As Integer
Public uEdge As Integer
Public rc As RECT
Public lParam As IntPtr
End Structure
Enum ABMsg As Integer
ABM_NEW = 0
ABM_REMOVE = 1
ABM_QUERYPOS = 2
ABM_SETPOS = 3
ABM_GETSTATE = 4
ABM_GETTASKBARPOS = 5
ABM_ACTIVATE = 6
ABM_GETAUTOHIDEBAR = 7
ABM_SETAUTOHIDEBAR = 8
ABM_WINDOWPOSCHANGED = 9
ABM_SETSTATE = 10
End Enum
Enum ABNotify As Integer
ABN_STATECHANGE = 0
ABN_POSCHANGED
ABN_FULLSCREENAPP
ABN_WINDOWARRANGE
End Enum
Enum ABEdge As Integer
ABE_LEFT = 0
ABE_TOP
ABE_RIGHT
ABE_BOTTOM
End Enum
Private fBarRegistered As Boolean = False
<DllImport("SHELL32", CallingConvention:=CallingConvention.StdCall)>
Private Shared Function SHAppBarMessage(dwMessage As Integer, ByRef pData As APPBARDATA) As UInteger
End Function
<DllImport("USER32")>
Private Shared Function GetSystemMetrics(Index As Integer) As Integer
End Function
<DllImport("User32.dll", ExactSpelling:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)>
Private Shared Function MoveWindow(hWnd As IntPtr, x As Integer, y As Integer, cx As Integer, cy As Integer, repaint As Boolean) As Boolean
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto)>
Private Shared Function RegisterWindowMessage(msg As String) As Integer
End Function
Private uCallBack As Integer
Private Sub RegisterBar()
Dim abd As New APPBARDATA()
abd.cbSize = Marshal.SizeOf(abd)
abd.hWnd = Me.Handle
If Not fBarRegistered Then
uCallBack = RegisterWindowMessage("AppBarMessage")
abd.uCallbackMessage = uCallBack
Dim ret As UInteger = SHAppBarMessage(CInt(ABMsg.ABM_NEW), abd)
fBarRegistered = True
ABSetPos()
Else
SHAppBarMessage(CInt(ABMsg.ABM_REMOVE), abd)
fBarRegistered = False
End If
End Sub
Private Sub ABSetPos()
Dim abd As New APPBARDATA()
abd.cbSize = Marshal.SizeOf(abd)
abd.hWnd = Me.Handle
abd.uEdge = CInt(ABEdge.ABE_TOP)
If abd.uEdge = CInt(ABEdge.ABE_LEFT) OrElse abd.uEdge = CInt(ABEdge.ABE_RIGHT) Then
abd.rc.top = 0
abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height
If abd.uEdge = CInt(ABEdge.ABE_LEFT) Then
abd.rc.left = 0
abd.rc.right = Size.Width
Else
abd.rc.right = SystemInformation.PrimaryMonitorSize.Width
abd.rc.left = abd.rc.right - Size.Width
End If
Else
abd.rc.left = 0
abd.rc.right = SystemInformation.PrimaryMonitorSize.Width
If abd.uEdge = CInt(ABEdge.ABE_TOP) Then
abd.rc.top = 0
abd.rc.bottom = Size.Height
Else
abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height
abd.rc.top = abd.rc.bottom - Size.Height
End If
End If
' Query the system for an approved size and position.
SHAppBarMessage(CInt(ABMsg.ABM_QUERYPOS), abd)
' Adjust the rectangle, depending on the edge to which the
' appbar is anchored.
Select Case abd.uEdge
Case CInt(ABEdge.ABE_LEFT)
abd.rc.right = abd.rc.left + Size.Width
Exit Select
Case CInt(ABEdge.ABE_RIGHT)
abd.rc.left = abd.rc.right - Size.Width
Exit Select
Case CInt(ABEdge.ABE_TOP)
abd.rc.bottom = abd.rc.top + Size.Height
Exit Select
Case CInt(ABEdge.ABE_BOTTOM)
abd.rc.top = abd.rc.bottom - Size.Height
Exit Select
End Select
' Pass the final bounding rectangle to the system.
SHAppBarMessage(CInt(ABMsg.ABM_SETPOS), abd)
' Move and size the appbar so that it conforms to the
' bounding rectangle passed to the system.
MoveWindow(abd.hWnd, abd.rc.left, abd.rc.top, abd.rc.right - abd.rc.left, abd.rc.bottom - abd.rc.top, True)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = uCallBack Then
Select Case m.WParam.ToInt32()
Case CInt(ABNotify.ABN_POSCHANGED)
ABSetPos()
Exit Select
End Select
End If
MyBase.WndProc(m)
End Sub
Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.Style = cp.Style And (Not &HC00000)
' WS_CAPTION
cp.Style = cp.Style And (Not &H800000)
' WS_BORDER
cp.ExStyle = &H80 Or &H8
' WS_EX_TOOLWINDOW | WS_EX_TOPMOST
Return cp
End Get
End Property
I'm not sure if the answer is going to be overriding something in CreateParams, or what, but it doesn't seem to be possible with BackColor/Transparency Key, Argb, or Opacity...
Thanks in advance.

Adding border to scrollable component

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

Serialization with collection property

Ok, so ive written a control that hosts multiple touch screen buttons. This control does this through the manipulation of a collection property marked with the attribute. Now it serializes these buttons in the InitializeComponent() sub that the designer creates for forms. However, whenever I delete the main control(the one that hosts the buttons), the designer doesnt remove the serialization code for the buttons in InitializeComponent() but even worse than that. If I copy the main control from one form and paste it into another form, the buttons aren't copied.
Here is the Code for the ButtonRow object:
Public Class ButtonRow
Inherits Control
Private WithEvents g_colTouchKeys As New TouchScreenButtonCollection
Private g_iMargin As Integer = 0
Public Sub New()
MyBase.DoubleBuffered = True
End Sub
<DefaultValue(0I)> _
Public Property ButtonMargin() As Integer
Get
Return g_iMargin
End Get
Set(ByVal value As Integer)
g_iMargin = value
End Set
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _ Editor(GetType(ButtonCollectionEditor), GetType(UITypeEditor))> _
Public ReadOnly Property Keys() As TouchScreenButtonCollection
Get
Return g_colTouchKeys
End Get
End Property
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
If MyBase.DesignMode Then
ArrangeButtons()
RenderButtons(e.Graphics)
Else
SetupButtons()
End If
End Sub
Private Sub ArrangeButtons()
Dim icl As Integer = 0
For Each B As TouchScreenKey In g_colTouchKeys
B.Top = 0
B.Left = icl
icl += g_iMargin + B.Width
Next
End Sub
Private Sub AddButtonToControlSurface()
For Each B As TouchScreenKey In g_colTouchKeys
If HasControl(B) = False Then MyBase.Controls.Add(B)
Next
End Sub
Private Sub RemoveControlsNotInCollection()
For Each C As Control In MyBase.Controls
If TypeOf C Is TouchScreenKey Then
If ButtonInCollection(DirectCast(C, TouchScreenKey)) = False Then
MyBase.Controls.Remove(C)
End If
End If
Next
End Sub
Private Function ButtonInCollection(ByVal B As TouchScreenKey) As Boolean
For Each BT As TouchScreenKey In g_colTouchKeys
If BT Is B Then Return True
Next
Return False
End Function
Private Function HasControl(ByVal C As Control) As Boolean
For Each Ct As Control In MyBase.Controls
If C Is Ct Then Return True
Next
Return False
End Function
Private Function CreateDefaultControl() As TouchScreenKey
Dim t As New TouchScreenKey(0, "Default")
t.Left = 0
t.Top = 0
t.Size = New Size(70, 70)
Return t
End Function
Private Sub RenderButtons(ByVal g As Graphics)
For Each B As TouchScreenKey In g_colTouchKeys
Dim rect As Rectangle = New Rectangle(B.Left, B.Top, B.Width, B.Height)
B.PaintButton(g, rect)
Next
End Sub
Private Sub SetupButtons()
ArrangeButtons()
RemoveControlsNotInCollection()
AddButtonToControlSurface()
End Sub
End Class
This is a sample of the InitilizeComponent() procedure after placing the ButtonRow object and adding 3 buttons to its collection:
Private Sub InitializeComponent()
Me.ButtonRow1 = New TouchPadControls.ButtonRow
Me.TouchScreenKey1 = New TouchPadControls.TouchScreenKey
Me.TouchScreenKey2 = New TouchPadControls.TouchScreenKey
Me.TouchScreenKey3 = New TouchPadControls.TouchScreenKey
Me.SuspendLayout()
'
'ButtonRow1
'
Me.ButtonRow1.Keys.AddRange(New TouchPadControls.TouchScreenKey() {Me.TouchScreenKey1, Me.TouchScreenKey2, Me.TouchScreenKey3})
Me.ButtonRow1.Location = New System.Drawing.Point(12, 12)
Me.ButtonRow1.Name = "ButtonRow1"
Me.ButtonRow1.Size = New System.Drawing.Size(321, 111)
Me.ButtonRow1.TabIndex = 0
Me.ButtonRow1.Text = "ButtonRow1"
'
'TouchScreenKey1
'
Me.TouchScreenKey1.ButtonPressGenerates = ""
Me.TouchScreenKey1.Location = New System.Drawing.Point(0, 0)
Me.TouchScreenKey1.Name = "TouchScreenKey1"
Me.TouchScreenKey1.Size = New System.Drawing.Size(80, 80)
Me.TouchScreenKey1.TabIndex = 0
Me.TouchScreenKey1.Text = "TouchScreenKey1"
'
'TouchScreenKey2
'
Me.TouchScreenKey2.ButtonPressGenerates = ""
Me.TouchScreenKey2.Location = New System.Drawing.Point(80, 0)
Me.TouchScreenKey2.Name = "TouchScreenKey2"
Me.TouchScreenKey2.Size = New System.Drawing.Size(80, 80)
Me.TouchScreenKey2.TabIndex = 0
Me.TouchScreenKey2.Text = "TouchScreenKey2"
'
'TouchScreenKey3
'
Me.TouchScreenKey3.ButtonPressGenerates = ""
Me.TouchScreenKey3.Location = New System.Drawing.Point(160, 0)
Me.TouchScreenKey3.Name = "TouchScreenKey3"
Me.TouchScreenKey3.Size = New System.Drawing.Size(80, 80)
Me.TouchScreenKey3.TabIndex = 0
Me.TouchScreenKey3.Text = "TouchScreenKey3"
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(449, 305)
Me.Controls.Add(Me.ButtonRow1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
I found the solution to this problem. All I had to do was dispose of the controls to delete them and use a ControlDesigner component to associate child controls with a main control.