Link to home
Start Free TrialLog in
Avatar of xersoft
xersoft

asked on

Designing a simple drop down list box control from scratch

Hi,
I’m trying to create a drop down control from scratch. I’m running into one problem so far: The actual drop down part of the box. So far I was thinking that making a separate form and managing its position would work. So I did that and it works great. The control would work for many applications the way it is. The problem is that I need to call dropdownform.show and this deactivates the form the actual drop down control lives on. I’ve attempted to put the code up in this message.

The question is how do I make a control that will ‘float’ over everything else (the window with the drop down selections in it) that does not deactivate the container control for the drop down.

Thanks for any help.


Control:
Public Class DropDownList
    Inherits System.Windows.Forms.UserControl

    'dropdownbutton
    Private mDropDownRegion As Drawing.Region

    'drop down form
    Dim WithEvents dropDownfrm As frmComboDrop
    Dim dropDownfrmHeight As Integer = 100
    Dim DropDownDirection As Integer = 1
    Dim Showingdropdownfrm As Boolean = False

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        Me.SetStyle(Windows.Forms.ControlStyles.DoubleBuffer Or Windows.Forms.ControlStyles.UserPaint Or Windows.Forms.ControlStyles.AllPaintingInWmPaint, True)
        Me.UpdateStyles()


        dropDownfrm = New frmComboDrop

    End Sub

    'UserControl overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents tmrShowForm As System.Windows.Forms.Timer
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Me.tmrShowForm = New System.Windows.Forms.Timer(Me.components)
        '
        'tmrShowForm
        '
        Me.tmrShowForm.Interval = 25
        '
        'DropDownList
        '
        Me.BackColor = System.Drawing.SystemColors.Window
        Me.Name = "DropDownList"
        Me.Size = New System.Drawing.Size(208, 20)

    End Sub

#End Region

    Private ReadOnly Property ClickBoxSize() As Integer
        Get
            Return Me.Size.Height
        End Get
    End Property
    <ComponentModel.Browsable(False)> Public ReadOnly Property Items() As ArrayList
        Get
            Return dropDownfrm.Items
        End Get
    End Property


    Private Sub DropDownList_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
        Me.Size = New Drawing.Size(Me.Size.Width, ClickBoxSize)
        Me.Invalidate()
    End Sub
    Private Sub DropDownList_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        Dim DropDownButtonRect As New Drawing.Rectangle(Me.Size.Width - ClickBoxSize - 1, 0, ClickBoxSize, ClickBoxSize - 1)
        Dim TextBoxAreaRect As New Drawing.Rectangle(0, 0, Me.Size.Width - DropDownButtonRect.Width, Me.Size.Height - 1)
        Dim SymbolFont As New Drawing.Font("Marlett", 16, Drawing.FontStyle.Regular, Drawing.GraphicsUnit.Pixel)
        Dim DownArrowSize As Drawing.Size = e.Graphics.MeasureString("6", SymbolFont).ToSize


        'draw the text box stuff
        e.Graphics.FillRectangle(Drawing.SystemBrushes.Window, TextBoxAreaRect)

        'text in text box area
        Dim TextSize As Drawing.Size = e.Graphics.MeasureString(Me.Text, Me.Font).ToSize
        Dim TextPoint As New Drawing.Point(0, CInt(TextBoxAreaRect.Height / 2 - TextSize.Height / 2))
        e.Graphics.DrawString(Me.Text, Me.Font, Drawing.SystemBrushes.ControlText, TextPoint.X, TextPoint.Y)


        'draw button
        e.Graphics.FillRectangle(Drawing.SystemBrushes.Control, DropDownButtonRect)
        'draw button text
        Dim ButtonTextPoint As New Drawing.Point(DropDownButtonRect.X + CInt(DropDownButtonRect.Width / 2 - DownArrowSize.Width / 2), DropDownButtonRect.Y + CInt(DropDownButtonRect.Height / 2 - DownArrowSize.Height / 2))
        e.Graphics.DrawString("6", SymbolFont, Drawing.SystemBrushes.ControlText, ButtonTextPoint.X, ButtonTextPoint.Y)
        'button border
        e.Graphics.DrawRectangle(Drawing.SystemPens.ControlText, DropDownButtonRect)









        If Not mDropDownRegion Is Nothing Then
            mDropDownRegion.Dispose()
        End If
        mDropDownRegion = New Drawing.Region(DropDownButtonRect)
    End Sub
    Private Sub DropDownList_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If Not mDropDownRegion Is Nothing Then
            If mDropDownRegion.IsVisible(e.X, e.Y) Then
                Dim button As New Windows.Forms.Button
                button.Location = New Drawing.Point(10, 10)
                button.Show()
                'ShowDropDown()
            End If
        End If
    End Sub


    Private Sub ShowDropDown()
        If Showingdropdownfrm = False Then
            dropDownfrm.Size = New Drawing.Size(Me.Size.Width, 10)
            dropDownfrm.Location = Me.PointToScreen(New Drawing.Point(0, Me.Height))
            dropDownfrm.TopMost = True
            dropDownfrm.Show()
            tmrShowForm.Enabled = True
            Showingdropdownfrm = True
            DropDownDirection = 1
            'dropDownfrm.Focus()
        End If
    End Sub
    Private Sub dropDownfrm_HideMeEvent(ByVal sender As Object, ByVal e As System.EventArgs) Handles dropDownfrm.HideMeEvent
        DropDownDirection = -1
        tmrShowForm.Enabled = True
    End Sub

    Private Sub tmrShowForm_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrShowForm.Tick
        If Showingdropdownfrm Then
            Dim NewHeight As Integer = dropDownfrm.Size.Height
            NewHeight += DropDownDirection * Convert.ToInt32(dropDownfrmHeight / 3)
            If NewHeight > dropDownfrmHeight Then
                NewHeight = dropDownfrmHeight
                tmrShowForm.Enabled = False
            End If
            If NewHeight < 0 Then
                dropDownfrm.Hide()
                Showingdropdownfrm = False
                tmrShowForm.Enabled = False
                Exit Sub
            End If


            dropDownfrm.Size = New Drawing.Size(Me.Size.Width, NewHeight)
            dropDownfrm.Location = Me.PointToScreen(New Drawing.Point(0, Me.Height))

        End If
    End Sub

    Private Sub dropDownfrm_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles dropDownfrm.TextChanged
        Me.Text = DirectCast(sender, frmComboDrop).Text
    End Sub
    Private Sub DropDownList_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.TextChanged
        Me.Invalidate()
    End Sub

End Class

'probably put this in another file?
Friend Class frmComboDrop
    Inherits System.Windows.Forms.Form

    Public Event HideMeEvent(ByVal sender As Object, ByVal e As EventArgs)

    Private mItems As New ArrayList


#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        Me.SetStyle(Windows.Forms.ControlStyles.Selectable, False)
        Me.UpdateStyles()

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        '
        'frmComboDrop
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.AutoScroll = True
        Me.BackColor = System.Drawing.SystemColors.Window
        Me.ClientSize = New System.Drawing.Size(164, 100)
        Me.ControlBox = False
        Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
        Me.Name = "frmComboDrop"
        Me.ShowInTaskbar = False
        Me.StartPosition = System.Windows.Forms.FormStartPosition.Manual

    End Sub

#End Region

    Public ReadOnly Property Items() As ArrayList
        Get
            Return mItems
        End Get
    End Property

    Private Sub Item_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        Me.Text = DirectCast(sender, Windows.Forms.LinkLabel).Text
        RaiseEvent HideMeEvent(Me, New EventArgs)
    End Sub

    Private Sub frmComboDrop_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.GotFocus
        'show all the data
        Me.Controls.Clear()
        For Each itm As Object In Items
            Dim lnk As New Windows.Forms.LinkLabel
            lnk.Text = itm.ToString
            lnk.AutoSize = True
            lnk.LinkBehavior = Windows.Forms.LinkBehavior.HoverUnderline
            AddHandler lnk.Click, AddressOf Item_Click

            lnk.Location = New Drawing.Point(0, Me.Controls.Count * (lnk.Size.Height + 1))
            Me.Controls.Add(lnk)
        Next
    End Sub

    Private Sub frmComboDrop_Deactivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Deactivate
        RaiseEvent HideMeEvent(Me, New EventArgs)
    End Sub

End Class
Avatar of xersoft
xersoft

ASKER

I'm very sorry there is a mistake in the above code please replace the following with what follows that

'CLASS: DropDownList


'bad code
Private Sub DropDownList_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If Not mDropDownRegion Is Nothing Then
            If mDropDownRegion.IsVisible(e.X, e.Y) Then
                Dim button As New Windows.Forms.Button
                button.Location = New Drawing.Point(10, 10)
                button.Show()
                'ShowDropDown()
            End If
        End If
    End Sub



'good code
    Private Sub DropDownList_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If Not mDropDownRegion Is Nothing Then
            If mDropDownRegion.IsVisible(e.X, e.Y) Then
                ShowDropDown()
            End If
        End If
    End Sub
ASKER CERTIFIED SOLUTION
Avatar of GohdanTheMoblin
GohdanTheMoblin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial