Transparent App Bar Winforms - vb.net

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.

Related

How can I scroll a ListView by one row instead of the default three using the mouse wheel?

I have a modified ListView. When I scroll using the mouse wheel, it scrolls three rows.
I want it to scroll one row at a time using the mouse wheel.
Public Class listviewEx
Inherits ListView
Private Declare Function ShowScrollBar Lib "user32" (ByVal hwnd As IntPtr, ByVal wBar As Integer,
ByVal bShow As Boolean) As Integer
' Constants
Private Const SB_HORZ As Integer = 0
Private Const WM_HSCROLL As Integer = &H114
Private Const WM_VSCROLL As Integer = &H115
Public Event Scroll As ScrollEventHandler
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
ShowScrollBar(MyBase.Handle, SB_HORZ, False)
If m.Msg = &H115 Then
' Trap WM_VSCROLL
End If
End Sub
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
End Class
You can add a behavior to your ListView, to make it scroll one row instead of the default three, using the Ctrl key (as this modifier is often used to change this kind of behaviors) in combination with the mouse wheel.
You can then have the standard three-rows scroll when Ctrl is not pressed and one-row scroll behavior when it's pressed.
Override WndProc (as you're already doing), to handle WM_MOUSEWHEEL and verify that the Ctrl key is pressed, checking whether the low-word of WParam is MK_CONTROL = &H08.
When it's pressed, determine whether the delta is positive or negative and increment the value returned by ListView.TopItem.Index to then set the TopItem based on the calculated offset (adding a minimum/maximum check to avoid overflows):
Imports System.Windows.Forms
Public Class ListViewEx
Inherits ListView
Private Const WM_MOUSEWHEEL As Integer = &H20A
Private Const MK_CONTROL As Integer = &H8
Public Sub New()
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
Select Case m.Msg
Case WM_MOUSEWHEEL
If Items.Count > 0 AndAlso (m.WParam.ToInt64() And &HFF) = MK_CONTROL Then
Dim offset = If((m.WParam.ToInt64() >> 16) > 0, -1, 1) + TopItem.Index
offset = Math.Max(Math.Min(offset, Items.Count - 1), 0)
TopItem = Items(offset)
m.Result = IntPtr.Zero
End If
End Select
End Sub
End Class
Someone named Viorel did it:
Public Class listviewEx
Inherits ListView
Protected Overrides Sub WndProc(ByRef m As Message)
Const WM_MOUSEWHEEL = &H20A
Select Case m.Msg
Case WM_MOUSEWHEEL
If TopItem IsNot Nothing Then
Dim d As Int16 = (m.WParam.ToInt32 >> 16)
Dim i As Integer
If d > 0 Then
i = Math.Max(TopItem.Index - 1, 0)
Else
i = Math.Min(TopItem.Index + 1, Items.Count - 1)
End If
TopItem = Items(i)
End If
m.Result = IntPtr.Zero
Return
End Select
MyBase.WndProc(m)
End Sub
End Class

Execute a application and wait for it to be loaded

I'm searching for a way to execute Steam (Steam.exe) and wait for it to be loaded (Not to exited).
I was think a good idea is to list all the child handles and search for a string in the title handles because when steam loads exist a window handle named "Friends", but this is hard to do it for me (APIs) so maybe exist a easy way to wait for a program to load...
Example of what I will do:
' First process
Process.start("Process 1.exe")
' Here will goes an efficient method to wait for application is loaded,
' not sleeping X seconds measuring the loading time or any of that.
' Second process
' Depends on first process fully loaded.
' If first process is not fully loaded (libraries and that) then this process can't run.
Process.start("Processs 2.exe")
UPDATE:
The Main question is how to wait for X process to be loaded, but about the Steam.exe I've noticed too when Steam is loaded tries to read/open some regkeys:
http://img267.imageshack.us/img267/6599/prtscrcapture4u.jpg
Maybe I can do something with code to monitor if one of that RegKeys is accesed?
Something like this?:
Dim RegKey = "HKLM\...blablabla"
Process.start("steam.exe")
While not Regkey.IsAccessed
' Do nothing and wait
Loop
Process.start("Second process.exe")
UPDATE 2:
I'm trying to make a function taking by reference the solution of Amegon, I don't finished the code because I'm getting an error in the line:
Memory = hprocess.PrivateMemorySize64
But I only get the error when I try to launch a "big" application (application that needs much time to load like Photoshop), with "little" apps works good.
Please if someone can help me to simplify/improve the Amegon's solution to make a Generic function and to correct the memory overflow error... Thank you!
This is my code:
' This is the sub that launchs the unfinished function:
Private Sub Launch_Game()
'Wait_For_Application_To_Load("C:\Games\Steam.exe", "-applaunch 0")
Wait_For_Application_To_Load("C:\Program Files\Adobe Photoshop CS6 (64 Bit)\Photoshop.exe")
End Sub
Private Function Wait_For_Application_To_Load(ByVal APP_Path As String, Optional ByVal APP_Arguments As String = Nothing)
Dim File = My.Computer.FileSystem.GetFileInfo(APP_Path)
Process.Start(APP_Path, APP_Arguments)
Timer_CheckCPU.Tag = File.Name.Substring(0, File.Name.Length - 4) ' Photoshop
Timer_CheckCPU.Enabled = True
End Function
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Private WithEvents Timer_CheckCPU As New Timer
Dim Memory_Value_Changed As Boolean
Dim CPU_Changed As Boolean
Dim CPU_Time As Boolean
Dim Running_Time As Boolean
Private _desiredTime_ms As Integer = 1500
Private Sub Timer_CheckCPU_Tick(sender As Object, ev As EventArgs) Handles Timer_CheckCPU.Tick
Timer_CheckCPU.Enabled = False
Dim pProcess() As Process = System.Diagnostics.Process.GetProcessesByName(Timer_CheckCPU.Tag)
Dim hprocess As Process = pProcess(0)
If hprocess Is Nothing Then
Running = False
Timer_CheckCPU.Enabled = True
Return
End If
Running = True
' Here is the error:
Memory = hprocess.PrivateMemorySize64
' MsgBox(hprocess.PrivateMemorySize64.ToString)
CPUTotal = hprocess.TotalProcessorTime.TotalMilliseconds
If AllConditionsGood() Then
If Not (_countdown.IsRunning) Then
_countdown.Reset()
_countdown.Start()
End If
Dim _elapsed As Integer = _countdown.ElapsedMilliseconds
If _elapsed >= _desiredTime_ms Then
Me.TopMost = True
MsgBox("process loaded")
Return
End If
Else
_countdown.Reset()
End If
Timer_CheckCPU.Enabled = True
End Sub
Private Function AllConditionsGood() As Boolean
If CPU_Time Then Return False
If Memory_Value_Changed Then Return False
If Running_Time Then Return False
Return True
End Function
Private _countdown As New Stopwatch
Private _Running As Boolean = False
Public WriteOnly Property Running() As Boolean
Set(ByVal value As Boolean)
_Running = value
If value Then
Running_Time = False
Else
Running_Time = True
End If
End Set
End Property
Private _CPUTotal As Integer
Public WriteOnly Property CPUTotal() As Integer
Set(ByVal value As Integer)
CPU = value - _CPUTotal 'used cputime since last check
_CPUTotal = value
End Set
End Property
Private _CPU As Integer
Public WriteOnly Property CPU() As Integer
Set(ByVal value As Integer)
If value = 0 Then
CPU_Time = False
Else
CPU_Time = True
End If
_CPU = value
End Set
End Property
Private _Memory As Integer
Public WriteOnly Property Memory() As Integer
Set(ByVal value As Integer)
MemoryDiff = Math.Abs(value - _Memory)
_Memory = value
End Set
End Property
Private _MemoryDiff As Integer
Public WriteOnly Property MemoryDiff() As Integer
Set(ByVal value As Integer)
If value = _MemoryDiff Then
Memory_Value_Changed = False
Else
Memory_Value_Changed = True
End If
_MemoryDiff = value
End Set
End Property
The WaitForInputIdle method waits until the application has started and is waiting for input
Dim psi As New ProcessStartInfo("fileName", "arguments")
Dim p As New Process
p.StartInfo = psi
p.Start()
p.WaitForInputIdle()
Note: This will not work for service applications.
Update I have build an example program to show this memory and cpu observing
To run it create a new project, windows form application, then open the code part and insert the following code. -no need to add any controls, I added them in code manually. I as able to successfully run the code with VS 2012 ultimate on win8 prof x64- :
Option Strict On
Imports System.Runtime.InteropServices
Public Class Form1
Private WithEvents btnStart As New Button
Private WithEvents tmrCheckCPU As New Timer
Private tbRunning As New TextBox
Private tbCPU As New TextBox
Private tbMemory As New TextBox
Private tbTime As New TextBox
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Size = New Size(400, 400)
With btnStart
'.Text = "Start DxDiag"
.Text = "Start Photoshop"
Me.Controls.Add(btnStart)
.Location = New Point(50, 50)
.Size = New Size(200, 50)
End With
With tmrCheckCPU
.Interval = 100
.Enabled = False
End With
With tbRunning
Me.Controls.Add(tbRunning)
.Location = New Point(50, 110)
.Size = New Size(100, 40)
End With
With tbCPU
Me.Controls.Add(tbCPU)
.Location = New Point(50, 150)
.Size = New Size(100, 40)
End With
With tbMemory
Me.Controls.Add(tbMemory)
.Location = New Point(50, 200)
.Size = New Size(100, 40)
End With
With tbTime
Me.Controls.Add(tbTime)
.Location = New Point(50, 250)
.Size = New Size(100, 40)
End With
End Sub
Private Sub btnStart_Clicked(sender As Object, ev As EventArgs) Handles btnStart.Click
'start Process
'Process.Start("dxdiag.exe", "/whql:on")
Process.Start("C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Photoshop.exe")
'start watching Timer
tmrCheckCPU.Enabled = True
End Sub
Private Function FindProcess(MainWindowTitle As String) As System.Diagnostics.Process
For Each ele As System.Diagnostics.Process In Process.GetProcesses
If ele.MainWindowTitle = MainWindowTitle Then Return ele
Next
Return Nothing
End Function
Private Sub tmrCheckCPU_Tick(sender As Object, ev As EventArgs) Handles tmrCheckCPU.Tick
tmrCheckCPU.Enabled = False
'Dim name As String = "DirectX Diagnostic Tool"
Dim name As String = "Adobe Photoshop CS6 Extended"
Dim hprocess As Process = FindProcess(name)
If hprocess Is Nothing Then
Running = False
tmrCheckCPU.Enabled = True
Return
End If
Running = True
Memory = hprocess.PrivateMemorySize64
CPUTotal = hprocess.TotalProcessorTime.TotalMilliseconds
If AllConditionsGood() Then
If Not (_countdown.IsRunning) Then
_countdown.Reset()
_countdown.Start()
End If
Dim _elapsed As Long = _countdown.ElapsedMilliseconds
If _elapsed >= _desiredTime_ms Then
tbTime.Text = _desiredTime_ms.ToString
tbTime.BackColor = Color.LightGreen
Me.TopMost = True
Me.Focus()
MsgBox("process loaded")
Return
Else
tbTime.Text = _elapsed.ToString
tbTime.BackColor = Color.LightGreen
End If
Else
_countdown.Reset()
End If
tmrCheckCPU.Enabled = True
End Sub
Private _desiredTime_ms As Integer = 1500
Private Function AllConditionsGood() As Boolean
If tbCPU.BackColor <> Color.LightGreen Then Return False
If tbMemory.BackColor <> Color.LightGreen Then Return False
If tbRunning.BackColor <> Color.LightGreen Then Return False
Return True
End Function
Private _countdown As New Stopwatch
Private _Running As Boolean = False
Public WriteOnly Property Running() As Boolean
Set(ByVal value As Boolean)
_Running = value
If value Then
tbRunning.Text = "Running"
tbRunning.BackColor = Color.LightGreen
Else
tbRunning.Text = "Not Running"
tbRunning.BackColor = Color.LightPink
End If
End Set
End Property
Private _CPUTotal As Double
Public WriteOnly Property CPUTotal() As Double
Set(ByVal value As Double)
CPU = value - _CPUTotal 'used cputime since last check
_CPUTotal = value
End Set
End Property
Private _CPU As Double
Public WriteOnly Property CPU() As Double
Set(ByVal value As Double)
If value = 0 Then
tbCPU.BackColor = Color.LightGreen
Else
tbCPU.BackColor = Color.LightPink
End If
_CPU = value
tbCPU.Text = value.ToString
End Set
End Property
Private _Memory As Long
Public WriteOnly Property Memory() As Long
Set(ByVal value As Long)
MemoryDiff = Math.Abs(value - _Memory)
_Memory = value
End Set
End Property
Private _MemoryDiff As Long
Public WriteOnly Property MemoryDiff() As Long
Set(ByVal value As Long)
If value = _MemoryDiff Then
tbMemory.BackColor = Color.LightGreen
Else
tbMemory.BackColor = Color.LightPink
End If
_MemoryDiff = value
tbMemory.Text = value.ToString
End Set
End Property
End Class
If you click on the button, it will start dxdiag and shows the change of memory and the difference of total cpu time (compared with last time) in textboxes. If all conditions are met (running, no cpu total time change, no memory change) then a stopwatch will count to 1500 and then a messagebox will say 'finished'
It is dirty written, but I guess you understand the main core (how to find the correct process without any dll declare method), how to read some information of that process after finding it, and in what way to apply the conditions.
The waiting time is meant to assure that a second of pure hard drive loading time will not create the wrong impression that loading is done (no memory or cpu change maybe).
The risk is that.. if a page will automatically appear and show content/advertisement, then maybe the cpu is constantly used. so you may only check for memory change or any other value tht you can access from the Process.
Update corrected code (fixed the wrong data types). Now Option strict is not complaining about my code :)

show text box in FolderBrowserDialog

how i can show textbox in FolderBrowserDialog like below image,
This is not directly possible, you have to fallback to using the shell function. Project + Add Reference, Browse tab, select c:\windows\system32\shell32.dll. An example of how to use it in a Winforms app:
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
Dim options As Integer = &H40 + &H200 + &H20
options += &H10 '' Adds edit box
Dim shell = New Shell32.ShellClass
Dim root = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Dim folder = CType(shell.BrowseForFolder(CInt(Me.Handle), _
"Select folder", options, root), Shell32.Folder2)
If folder IsNot Nothing Then
MsgBox("You selected " + folder.Self.Path)
End If
End Sub
Check this out : FolderBrowserDialogEx: A C# customization of FolderBrowserDialog
The code is in C#, Here is the VB Conversion
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Diagnostics
Namespace DaveChambers.FolderBrowserDialogEx
Public Class FolderBrowserDialogEx
#Region "Fields that mimic the same-named fields in FolderBrowserDialog"
Public Property RootFolder() As Environment.SpecialFolder
Get
Return m_RootFolder
End Get
Set
m_RootFolder = Value
End Set
End Property
Private m_RootFolder As Environment.SpecialFolder
Public Property SelectedPath() As String
Get
Return m_SelectedPath
End Get
Set
m_SelectedPath = Value
End Set
End Property
Private m_SelectedPath As String
Public Property ShowNewFolderButton() As Boolean
Get
Return m_ShowNewFolderButton
End Get
Set
m_ShowNewFolderButton = Value
End Set
End Property
Private m_ShowNewFolderButton As Boolean
Public Property StartPosition() As FormStartPosition
Get
Return m_StartPosition
End Get
Set
m_StartPosition = Value
End Set
End Property
Private m_StartPosition As FormStartPosition
#End Region
' Fields specific to CustomFolderBrowserDialog
Public Property Title() As String
Get
Return m_Title
End Get
Set
m_Title = Value
End Set
End Property
Private m_Title As String
Public Property ShowEditbox() As Boolean
Get
Return m_ShowEditbox
End Get
Set
m_ShowEditbox = Value
End Set
End Property
Private m_ShowEditbox As Boolean
' These are the control IDs used in the dialog
Private Structure CtlIds
Public Const PATH_EDIT As Integer = &H3744
'public const int PATH_EDIT_LABEL = 0x3748; // Only when BIF_NEWDIALOGSTYLE
Public Const TITLE As Integer = &H3742
Public Const TREEVIEW As Integer = &H3741
Public Const NEW_FOLDER_BUTTON As Integer = &H3746
Public Const IDOK As Integer = 1
Public Const IDCANCEL As Integer = 2
End Structure
<StructLayout(LayoutKind.Sequential, CharSet := CharSet.Unicode)> _
Public Structure InitData
' Titles shouldn't too long, should they?
<MarshalAs(UnmanagedType.ByValTStr, SizeConst := 128)> _
Public Title As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst := Win32.MAX_PATH)> _
Public InitialPath As String
Public ShowEditbox As Boolean
Public ShowNewFolderButton As Boolean
Public StartPosition As FormStartPosition
Public hParent As IntPtr
Public Sub New(dlg As FolderBrowserDialogEx, hParent As IntPtr)
' We need to make copies of these values from the dialog.
' I tried passing the dlg obj itself in this struct, but Windows will barf after repeated invocations.
Me.Title = dlg.Title
Me.InitialPath = dlg.SelectedPath
Me.ShowNewFolderButton = dlg.ShowNewFolderButton
Me.ShowEditbox = dlg.ShowEditbox
Me.StartPosition = dlg.StartPosition
Me.hParent = hParent
End Sub
End Structure
Public Sub New()
Title = "Browse For Folder"
' Default to same caption as std dialog
RootFolder = Environment.SpecialFolder.Desktop
SelectedPath = "c:\"
ShowEditbox = False
ShowNewFolderButton = False
StartPosition = FormStartPosition.WindowsDefaultLocation
End Sub
Public Function ShowDialog(owner As IWin32Window) As DialogResult
Dim initdata As New InitData(Me, owner.Handle)
Dim bi As New Win32.BROWSEINFO()
bi.iImage = 0
bi.hwndOwner = owner.Handle
If 0 <> Win32.SHGetSpecialFolderLocation(owner.Handle, CInt(Me.RootFolder), bi.pidlRoot) Then
bi.pidlRoot = IntPtr.Zero
End If
bi.lpszTitle = ""
bi.ulFlags = Win32.BIF_RETURNONLYFSDIRS
' do NOT use BIF_NEWDIALOGSTYLE or BIF_STATUSTEXT
If Me.ShowEditbox Then
bi.ulFlags = bi.ulFlags Or Win32.BIF_EDITBOX
End If
If Not Me.ShowNewFolderButton Then
bi.ulFlags = bi.ulFlags Or Win32.BIF_NONEWFOLDERBUTTON
End If
bi.lpfn = New Win32.BrowseCallbackProc(_browseCallbackHandler)
' Initialization data, used in _browseCallbackHandler
Dim hInit As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(initdata))
Marshal.StructureToPtr(initdata, hInit, True)
bi.lParam = hInit
Dim pidlSelectedPath As IntPtr = IntPtr.Zero
Try
pidlSelectedPath = Win32.SHBrowseForFolder(bi)
Dim sb As New StringBuilder(256)
If Win32.SHGetPathFromIDList(pidlSelectedPath, sb) Then
SelectedPath = sb.ToString()
Return DialogResult.OK
End If
Finally
' Caller is responsible for freeing this memory.
Marshal.FreeCoTaskMem(pidlSelectedPath)
End Try
Return DialogResult.Cancel
End Function
Private Function _browseCallbackHandler(hDlg As IntPtr, msg As Integer, lParam As IntPtr, lpData As IntPtr) As Integer
Select Case msg
Case Win32.BFFM_INITIALIZED
' remove context help button from dialog caption
Dim lStyle As Integer = Win32.GetWindowLong(hDlg, Win32.GWL_STYLE)
lStyle = lStyle And Not Win32.DS_CONTEXTHELP
Win32.SetWindowLong(hDlg, Win32.GWL_STYLE, lStyle)
lStyle = Win32.GetWindowLong(hDlg, Win32.GWL_EXSTYLE)
lStyle = lStyle And Not Win32.WS_EX_CONTEXTHELP
Win32.SetWindowLong(hDlg, Win32.GWL_EXSTYLE, lStyle)
_adjustUi(hDlg, lpData)
Exit Select
Case Win32.BFFM_SELCHANGED
If True Then
Dim ok As Boolean = False
Dim sb As New StringBuilder(Win32.MAX_PATH)
If Win32.SHGetPathFromIDList(lParam, sb) Then
ok = True
Dim dir As String = sb.ToString()
Dim hEdit As IntPtr = Win32.GetDlgItem(hDlg, CtlIds.PATH_EDIT)
Win32.SetWindowText(hEdit, dir)
#If UsingStatusText Then
' We're not using status text, but if we were, this is how you'd set it
Win32.SendMessage(hDlg, Win32.BFFM_SETSTATUSTEXTW, 0, dir)
#End If
#If SHBrowseForFolder_lists_links Then
' This check doesn't seem to be necessary - the SHBrowseForFolder dirtree doesn't seem to list links
Dim sfi As New Win32.SHFILEINFO()
Win32.SHGetFileInfo(lParam, 0, sfi, Marshal.SizeOf(sfi), Win32.SHGFI_PIDL Or Win32.SHGFI_ATTRIBUTES)
' fail if pidl is a link
If (sfi.dwAttributes And Win32.SFGAO_LINK) = Win32.SFGAO_LINK Then
ok = False
#End If
End If
End If
' if invalid selection, disable the OK button
If Not ok Then
Win32.EnableWindow(Win32.GetDlgItem(hDlg, CtlIds.IDOK), False)
End If
Exit Select
End If
End Select
Return 0
End Function
Private Sub _adjustUi(hDlg As IntPtr, lpData As IntPtr)
' Only do the adjustments if InitData was supplied
If lpData = IntPtr.Zero Then
Return
End If
Dim obj As Object = Marshal.PtrToStructure(lpData, GetType(InitData))
If obj Is Nothing Then
Return
End If
Dim initdata As InitData = DirectCast(obj, InitData)
' Only do the adjustments if we can find the dirtree control
Dim hTree As IntPtr = Win32.GetDlgItem(hDlg, CtlIds.TREEVIEW)
If hTree = IntPtr.Zero Then
hTree = Win32.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "SysTreeView32", IntPtr.Zero)
If hTree = IntPtr.Zero Then
' This usually means that BIF_NEWDIALOGSTYLE is enabled.
hTree = Win32.FindWindowEx(hDlg, IntPtr.Zero, "SHBrowseForFolder ShellNameSpace Control", IntPtr.Zero)
End If
End If
If hTree = IntPtr.Zero Then
Return
End If
' Prep the basic UI
Win32.SendMessage(hDlg, Win32.BFFM_SETSELECTIONW, 1, initdata.InitialPath)
Win32.SetWindowText(hDlg, initdata.Title)
If initdata.StartPosition = FormStartPosition.CenterParent Then
_centerTo(hDlg, initdata.hParent)
ElseIf initdata.StartPosition = FormStartPosition.CenterScreen Then
_centerTo(hDlg, Win32.GetDesktopWindow())
End If
' else we do nothing
' Prep the edit box
Dim rcEdit As New Win32.RECT()
Dim hEdit As IntPtr = Win32.GetDlgItem(hDlg, CtlIds.PATH_EDIT)
If hEdit <> IntPtr.Zero Then
If initdata.ShowEditbox Then
Win32.GetWindowRect(hEdit, rcEdit)
Win32.ScreenToClient(hEdit, rcEdit)
Else
Win32.ShowWindow(hEdit, Win32.SW_HIDE)
End If
End If
' make the dialog larger
Dim rcDlg As Win32.RECT
Win32.GetWindowRect(hDlg, rcDlg)
rcDlg.Right += 40
rcDlg.Bottom += 30
If hEdit <> IntPtr.Zero Then
rcDlg.Bottom += (rcEdit.Height + 5)
End If
Win32.MoveWindow(hDlg, rcDlg, True)
Win32.GetClientRect(hDlg, rcDlg)
Dim vMargin As Integer = 10
' Accomodate the resizing handle's width
Dim hMargin As Integer = 10
' SystemInformation.VerticalScrollBarWidth;
' Move the Cancel button
Dim rcCancel As New Win32.RECT()
Dim hCancel As IntPtr = Win32.GetDlgItem(hDlg, CtlIds.IDCANCEL)
If hCancel <> IntPtr.Zero Then
Win32.GetWindowRect(hCancel, rcCancel)
Win32.ScreenToClient(hDlg, rcCancel)
rcCancel = New Win32.RECT(rcDlg.Right - (rcCancel.Width + hMargin), rcDlg.Bottom - (rcCancel.Height + vMargin), rcCancel.Width, rcCancel.Height)
Win32.MoveWindow(hCancel, rcCancel, False)
End If
' Move the OK button
Dim rcOK As New Win32.RECT()
Dim hOK As IntPtr = Win32.GetDlgItem(hDlg, CtlIds.IDOK)
If hOK <> IntPtr.Zero Then
Win32.GetWindowRect(hOK, rcOK)
Win32.ScreenToClient(hDlg, rcOK)
rcOK = New Win32.RECT(rcCancel.Left - (rcCancel.Width + hMargin), rcCancel.Top, rcOK.Width, rcOK.Height)
Win32.MoveWindow(hOK, rcOK, False)
End If
' Manage the "Make New Folder" button
Dim hBtn As IntPtr = Win32.GetDlgItem(hDlg, CtlIds.NEW_FOLDER_BUTTON)
If Not initdata.ShowNewFolderButton Then
' Make sure this button is not visible
Win32.ShowWindow(hBtn, Win32.SW_HIDE)
ElseIf hBtn = IntPtr.Zero Then
' Create a button - button is only auto-created under BIF_NEWDIALOGSTYLE
' This is failing, and I don't know why!
hBtn = Win32.CreateWindowEx(&H50010000, "button", "&Make New Folder", &H4, hMargin, rcOK.Top, _
105, rcOK.Height, hDlg, New IntPtr(CtlIds.NEW_FOLDER_BUTTON), Process.GetCurrentProcess().Handle, IntPtr.Zero)
End If
' Position the path editbox and it's label
' We'll repurpose the Title (static) control as the editbox label
Dim treeTop As Integer = vMargin
If hEdit <> IntPtr.Zero Then
Dim xEdit As Integer = hMargin
Dim cxEdit As Integer = rcDlg.Width - (2 * hMargin)
Dim hLabel As IntPtr = Win32.GetDlgItem(hDlg, CtlIds.TITLE)
If hLabel <> IntPtr.Zero Then
Dim labelText As String = "Folder: "
Win32.SetWindowText(hLabel, labelText)
' This code obtains the required size of the static control that serves as the label for the editbox.
' All this GDI code is a bit excessive, but I figured "what the hell".
Dim hdc As IntPtr = Win32.GetDC(hLabel)
Dim hFont As IntPtr = Win32.SendMessage(hLabel, Win32.WM_GETFONT, IntPtr.Zero, IntPtr.Zero)
Dim oldfnt As IntPtr = Win32.SelectObject(hdc, hFont)
Dim szLabel As Size = Size.Empty
Win32.GetTextExtentPoint32(hdc, labelText, labelText.Length, szLabel)
Win32.SelectObject(hdc, oldfnt)
Win32.ReleaseDC(hLabel, hdc)
Dim rcLabel As New Win32.RECT(hMargin, vMargin + ((rcEdit.Height - szLabel.Height) / 2), szLabel.Width, szLabel.Height)
Win32.MoveWindow(hLabel, rcLabel, False)
xEdit += rcLabel.Width
cxEdit -= rcLabel.Width
End If
' Expand the folder tree to fill the dialog
rcEdit = New Win32.RECT(xEdit, vMargin, cxEdit, rcEdit.Height)
Win32.MoveWindow(hEdit, rcEdit, False)
treeTop = rcEdit.Bottom + 5
End If
Dim rcTree As New Win32.RECT(hMargin, treeTop, rcDlg.Width - (2 * hMargin), rcDlg.Bottom - (treeTop + (2 * vMargin) + rcOK.Height))
Win32.MoveWindow(hTree, rcTree, False)
End Sub
Private Sub _centerTo(hDlg As IntPtr, hRef As IntPtr)
Dim rcDlg As Win32.RECT
Win32.GetWindowRect(hDlg, rcDlg)
Dim rcRef As Win32.RECT
Win32.GetWindowRect(hRef, rcRef)
Dim cx As Integer = (rcRef.Width - rcDlg.Width) / 2
Dim cy As Integer = (rcRef.Height - rcDlg.Height) / 2
Dim rcNew As New Win32.RECT(rcRef.Left + cx, rcRef.Top + cy, rcDlg.Width, rcDlg.Height)
Win32.MoveWindow(hDlg, rcNew, True)
End Sub
End Class
End Namespace
'=======================================================
'Service provided by Telerik (www.telerik.com)
'Conversion powered by NRefactory.
'Twitter: #telerik, #toddanglin
'Facebook: facebook.com/telerik
'=======================================================
I see two issues with the above dialogboxes (and any other dialog I've seen):
1: You cannot specify a custom start folder which will be preselected when the dialogbox opens, let's say "c:\temp"
2: When you type a path in the textbox and push TAB or ENTER this should NOT be seen as the final selected folder, but the treeview should instead move and expand to that path (just as if you did the same in Windows Explorer).
(sorry for putting this as an answer, cannot make a comment)

How to create a seek slider in vb.net

I found many tutorials on youtube which tell us, how to use AxWindowsMediaPlayer and basic stuff like creating your own volume control using TrackBar1 for Windows Media Player Component. But now I want to ask that how we can create our own movie duration control using trackbar or a seek slider in vb.net for Windows Media Player. I have searched a lot but question still remains a question. I hope that many great developers of vb.net on this site, should tell me logic behind it
THANKS IN ADVANCE
The trick is to subclass the TrackBar control and handle the OnPaintBackground and OnPaint events.
Here's an "extra-lite" version of a control I use on some of my own projects.
This version is quite limited but it should help you get started...
Imports System.Drawing.Drawing2D
Public Class CoolTrackBar
Inherits TrackBar
Private thumbRect As Rectangle = New Rectangle(0, 0, 19, 19)
Private isOverThumb As Boolean
Private cachedValue As Integer
Private rangeRect As Rectangle = Rectangle.Empty
Private mGrooveSize As Integer = 6
Private mGrooveBorderColor As Color = Color.Gray
Private mGrooveColor As Color = Color.LightGray
Private mSelStartColor As Color = Color.Blue
Private mSelEndColor As Color = Color.Red
Public Sub New()
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.ResizeRedraw, True)
Me.SetStyle(ControlStyles.UserPaint, True)
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
End Sub
Public Property GrooveSize As Integer
Get
Return mGrooveSize
End Get
Set(value As Integer)
mGrooveSize = value
Me.Invalidate()
End Set
End Property
Public Property GrooveColor As Color
Get
Return mGrooveColor
End Get
Set(value As Color)
mGrooveColor = value
Me.Invalidate()
End Set
End Property
Public Property GrooveBorderColor As Color
Get
Return mGrooveBorderColor
End Get
Set(value As Color)
mGrooveBorderColor = value
Me.Invalidate()
End Set
End Property
Public Overloads Property TickStyle As TickStyle
Get
Return Windows.Forms.TickStyle.Both
End Get
Set(value As TickStyle)
MyBase.TickStyle = Windows.Forms.TickStyle.Both
End Set
End Property
Protected Overrides Sub OnPaintBackground(pevent As PaintEventArgs)
Dim g As Graphics = pevent.Graphics
Dim r As Rectangle = Me.DisplayRectangle
Select Case MyBase.Orientation
Case Orientation.Horizontal
rangeRect = New Rectangle(r.X + 14, r.Top, r.Width - 30, r.Height)
Case Orientation.Vertical
rangeRect = New Rectangle(r.X + 5, r.Y + 14, r.Width, r.Height - 29)
End Select
MyBase.OnPaintBackground(pevent)
DrawGroove(g)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim g As Graphics = e.Graphics
DrawThumb(g)
End Sub
Private Sub DrawGroove(g As Graphics)
Dim r1 As Rectangle
Dim r2 As Rectangle
Select Case Orientation
Case Windows.Forms.Orientation.Horizontal
r1 = New Rectangle(rangeRect.X, rangeRect.Y + (rangeRect.Height - mGrooveSize) \ 2, rangeRect.Width, mGrooveSize)
r2 = New Rectangle(r1.X, r1.Y, r1.Width * ValueToPercentage(cachedValue), r1.Height)
Case Windows.Forms.Orientation.Vertical
r1 = New Rectangle(rangeRect.X + (rangeRect.Width - mGrooveSize) / 2 - mGrooveSize \ 2, rangeRect.Y, mGrooveSize, rangeRect.Height)
r2 = New Rectangle(r1.X, r1.Y, r1.Width, r1.Height * ValueToPercentage(cachedValue))
End Select
Using b As New SolidBrush(mGrooveColor)
g.FillRectangle(b, r1)
End Using
Using p As New Pen(mGrooveBorderColor)
g.DrawRectangle(p, r1)
End Using
Using lgb As New LinearGradientBrush(r1.Location, New Point(r1.Right, r1.Bottom), mSelStartColor, mSelEndColor)
g.FillRectangle(lgb, r2)
End Using
End Sub
Private Sub DrawThumb(g As Graphics)
Dim thumb As VisualStyles.VisualStyleElement = Nothing
Select Case MyBase.Orientation
Case Orientation.Horizontal
If MyBase.Enabled Then
If isOverThumb Then
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbTop.Hot
Else
If MyBase.Focused Then
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbTop.Focused
Else
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbTop.Normal
End If
End If
Else
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbTop.Disabled
End If
Case Orientation.Vertical
If MyBase.Enabled Then
If isOverThumb Then
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbRight.Hot
Else
If MyBase.Focused Then
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbRight.Focused
Else
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbRight.Normal
End If
End If
Else
thumb = VisualStyles.VisualStyleElement.TrackBar.ThumbRight.Disabled
End If
End Select
Dim valuePercentage As Single = ValueToPercentage(cachedValue)
Dim vsr = New VisualStyles.VisualStyleRenderer(thumb)
thumbRect.Size = vsr.GetPartSize(g, VisualStyles.ThemeSizeType.Draw)
Dim pos As Integer
Select Case MyBase.Orientation
Case Orientation.Horizontal
pos = valuePercentage * rangeRect.Width
thumbRect.Location = New Point(pos + thumbRect.Width / 2 + 3, rangeRect.Y + thumbRect.Height / 2 + mGrooveSize / 4)
Case Orientation.Vertical
pos = valuePercentage * rangeRect.Height
thumbRect.Location = New Point(rangeRect.X + thumbRect.Width / 2 + mGrooveSize / 4, pos + thumbRect.Height / 2 + 3)
End Select
vsr.DrawBackground(g, thumbRect)
End Sub
Private Function ValueToPercentage(value As Integer) As Single
Dim w As Integer = MyBase.Maximum - MyBase.Minimum
Dim min = MyBase.Minimum
Dim max = MyBase.Maximum
If MyBase.Orientation = Orientation.Horizontal Then
Return (value - min) / (max - min)
Else
Return 1 - (value - min) / (max - min)
End If
End Function
Private Sub CoolTrackBar_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
If thumbRect.IntersectsWith(New Rectangle(e.Location, New Size(1, 1))) Then
isOverThumb = True
Me.Invalidate()
ElseIf isOverThumb Then
isOverThumb = False
Me.Invalidate()
End If
End Sub
Private Sub CoolTrackBar_ValueChanged(sender As Object, e As EventArgs) Handles Me.ValueChanged
cachedValue = MyBase.Value
Me.Invalidate()
End Sub
End Class
To use it, simply create a WinForms project, then create a new Class, name it CoolTrackBar and paste the code above.
You'll need to compile the solution for the control to appear on your Toolbox.

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.