none
UserControl - Adding panel which is in front of other forms RRS feed

  • Question

  • Hello all,

    I am creating a dropdown usercontrol. When the user clicks the control a panel is created showing the dropdown options to select from. Now the problem is that the panel is limited to the form which is the parent of the usercontrol. What I would like to achieve, though, is to have this in front of all open windows (same as with the windows dropdown box).

    Is it possible to use a form created from within the control instead? Or are there other options?

    Best regards,

    Christian

    Wednesday, April 11, 2018 8:19 AM

Answers

  •  It is not clear to me if the 'DropDown' is created from in your UserControl or if you want the UserControl as the 'DropDown'.  Either way,  you can add a Panel,  UserControl,  or any other control you want to a new instance of a ToolStripControlHost.  Then you can add that to a new instance of a ToolStripDropDown.  The ToolStripDropDown will do what you want when it is Shown,  it will be on top of all other windows.  You just call one of it's Show method and supply the position you want it shown.

     From there,  it will close when the ToolStripDropDown looses focus,  like if you click elsewhere on the form or screen.  However,  it can also be set up to stay open until you call it's Close method or the Form looses focus.

     For example, here I add a UserControl to a ToolStripControlHost and then add that to a ToolStripDropDown.  I call it's Show method from a Button Click event to show it right below the button.

    Public Class Form1
        Private WithEvents MyUserCtrl As New MyUserControl With {.MinimumSize = .Size}
        Private WithEvents ucDropDown As New ToolStripDropDown
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim tsmiHost As New ToolStripControlHost(MyUserCtrl) 'you can add a Panel or whatever control you want to the ToolStripControlHost, I am adding a UserControl
            tsmiHost.Margin = New Padding(0)
            ucDropDown.Padding = New Padding(0)
            ucDropDown.Items.Add(tsmiHost)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim pts As Point = Me.PointToScreen(Button1.Location)
            ucDropDown.Show(pts.X, pts.Y + Button1.Height)
        End Sub
    
        Private Sub MyUserCtrl_SaveButtonClicked(sender As Object, e As EventArgs) Handles MyUserCtrl.SaveButtonClicked
            ucDropDown.Close() 'calls close when the Save button on the UserControl is clicked
        End Sub
    End Class
     

     This shows the example above in action...

     

     

     As said,  you can stop the DropDown from closing unless the user actually calls it's Close method or the Form looses focus.  This also requires moving the DropDown with the Form as it is moved if you want it to stay in a specific spot,  like below a button or other control.

    Public Class Form1
        Private WithEvents MyUserCtrl As New MyUserControl With {.Left = 0, .Top = 0, .Dock = DockStyle.Fill}
        Private WithEvents ucDropDown As New ToolStripDropDown

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim tsmiHost As New ToolStripControlHost(MyUserCtrl)
            tsmiHost.Margin = New Padding(0)
            ucDropDown.Padding = New Padding(0)
            ucDropDown.Items.Add(tsmiHost)
        End Sub

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If ucDropDown.Visible Then
                ucDropDown.Close()
                Button1.Text = "Open Options"
            Else
                Dim pts As Point = Me.PointToScreen(Button1.Location)
                ucDropDown.Show(pts.X, pts.Y + Button1.Height)
                Button1.Text = "Close Options"
            End If
        End Sub

        Private Sub ucDropDown_Closing(sender As Object, e As ToolStripDropDownClosingEventArgs) Handles ucDropDown.Closing
            e.Cancel = Not (e.CloseReason = ToolStripDropDownCloseReason.CloseCalled OrElse e.CloseReason = ToolStripDropDownCloseReason.AppFocusChange)
            Button1.Text = If(e.Cancel, "Close Options", "Open Options")
        End Sub

        Private Sub Form1_LocationChanged(sender As Object, e As EventArgs) Handles Me.LocationChanged
            If ucDropDown.Visible Then
                Dim pts As Point = Me.PointToScreen(Button1.Location)
                ucDropDown.Location = New Point(pts.X, pts.Y + Button1.Height)
            End If
        End Sub

        Protected Overrides Sub WndProc(ByRef m As Message)
            If m.Msg = &H112 AndAlso m.WParam.ToInt32 = &HF020 AndAlso ucDropDown.Visible Then ucDropDown.Close() 'if the form is minimizing, then close the DropDown
            MyBase.WndProc(m)
        End Sub
    End Class
     

     Here you can see that the DropDown will not close until the (Close Options) button calls the Close method or the form looses focus.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Wednesday, April 11, 2018 6:27 PM Updated 2nd example to fix a bug when form is minimized
    • Proposed as answer by Mr. Monkeyboy Wednesday, April 11, 2018 9:45 PM
    • Marked as answer by ChrisP1980 Thursday, April 26, 2018 9:18 AM
    Wednesday, April 11, 2018 6:03 PM

All replies

  • Hi Christian,

    I'm not sure If I can understand what you want to achieve. Could you insert a screenshot of your Form?
    If you cannot "insert" it, please share it via cloud storage (e.g. OneDrive, Dropbox, etc.).
    Regards,

    Ashidacchi -- http://hokusosha.com/

    Wednesday, April 11, 2018 8:42 AM
  • What I would like to achieve, though, is to have this in front of all open windows (same as with the windows dropdown box).
    The Listbox part of a ComboBox ("ComboLBox" class) is a child of the Desktop (and Topmost), allowing to overlap other controls

    • Edited by Castorix31 Wednesday, April 11, 2018 9:23 AM
    Wednesday, April 11, 2018 8:49 AM
  • Christian,

    Probably nobody hear knows what you mean with Windows dropdown box. 

    But maybe you mean the context menu, which opens when you right click. 


    Success
    Cor

    Wednesday, April 11, 2018 8:54 AM
  • Hi,

    OK, thanks. Is there any way I can do the same with my usercontrol's list part?

    Best regards,

    Christian

    Wednesday, April 11, 2018 9:00 AM
  • Sorry, I was referring to the post of Castorix31 in my last question.

    Just to make myself a bit clearer: In MS Forms there is a dropdown ("combo") box control available. Since I am not happy with that I have created my own dropdown box usercontrol. This works really well with the one exception that my dropdown list is limited to the form whereas the MS Forms dropdown list is not. It is shown above all other forms. As Castorix31 explained the reason is that the combobox control's dropdown list has the Desktop as its parent.

    Now I would need to know if I can do the same with the dropdown list panel of my own usercontrol.

    Wednesday, April 11, 2018 9:19 AM
  • The standard ComboBox uses SetParent on the "ComboLBox" window with NULL handle as parent (IntPtr.Zero) to make it child of the Desktop

    I tested quickly with an Edit control and it works if the WS_CHILD style is removed (with SetWindowLong) but not sure it can work for any control...

    Wednesday, April 11, 2018 10:39 AM
  •  It is not clear to me if the 'DropDown' is created from in your UserControl or if you want the UserControl as the 'DropDown'.  Either way,  you can add a Panel,  UserControl,  or any other control you want to a new instance of a ToolStripControlHost.  Then you can add that to a new instance of a ToolStripDropDown.  The ToolStripDropDown will do what you want when it is Shown,  it will be on top of all other windows.  You just call one of it's Show method and supply the position you want it shown.

     From there,  it will close when the ToolStripDropDown looses focus,  like if you click elsewhere on the form or screen.  However,  it can also be set up to stay open until you call it's Close method or the Form looses focus.

     For example, here I add a UserControl to a ToolStripControlHost and then add that to a ToolStripDropDown.  I call it's Show method from a Button Click event to show it right below the button.

    Public Class Form1
        Private WithEvents MyUserCtrl As New MyUserControl With {.MinimumSize = .Size}
        Private WithEvents ucDropDown As New ToolStripDropDown
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim tsmiHost As New ToolStripControlHost(MyUserCtrl) 'you can add a Panel or whatever control you want to the ToolStripControlHost, I am adding a UserControl
            tsmiHost.Margin = New Padding(0)
            ucDropDown.Padding = New Padding(0)
            ucDropDown.Items.Add(tsmiHost)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim pts As Point = Me.PointToScreen(Button1.Location)
            ucDropDown.Show(pts.X, pts.Y + Button1.Height)
        End Sub
    
        Private Sub MyUserCtrl_SaveButtonClicked(sender As Object, e As EventArgs) Handles MyUserCtrl.SaveButtonClicked
            ucDropDown.Close() 'calls close when the Save button on the UserControl is clicked
        End Sub
    End Class
     

     This shows the example above in action...

     

     

     As said,  you can stop the DropDown from closing unless the user actually calls it's Close method or the Form looses focus.  This also requires moving the DropDown with the Form as it is moved if you want it to stay in a specific spot,  like below a button or other control.

    Public Class Form1
        Private WithEvents MyUserCtrl As New MyUserControl With {.Left = 0, .Top = 0, .Dock = DockStyle.Fill}
        Private WithEvents ucDropDown As New ToolStripDropDown

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim tsmiHost As New ToolStripControlHost(MyUserCtrl)
            tsmiHost.Margin = New Padding(0)
            ucDropDown.Padding = New Padding(0)
            ucDropDown.Items.Add(tsmiHost)
        End Sub

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If ucDropDown.Visible Then
                ucDropDown.Close()
                Button1.Text = "Open Options"
            Else
                Dim pts As Point = Me.PointToScreen(Button1.Location)
                ucDropDown.Show(pts.X, pts.Y + Button1.Height)
                Button1.Text = "Close Options"
            End If
        End Sub

        Private Sub ucDropDown_Closing(sender As Object, e As ToolStripDropDownClosingEventArgs) Handles ucDropDown.Closing
            e.Cancel = Not (e.CloseReason = ToolStripDropDownCloseReason.CloseCalled OrElse e.CloseReason = ToolStripDropDownCloseReason.AppFocusChange)
            Button1.Text = If(e.Cancel, "Close Options", "Open Options")
        End Sub

        Private Sub Form1_LocationChanged(sender As Object, e As EventArgs) Handles Me.LocationChanged
            If ucDropDown.Visible Then
                Dim pts As Point = Me.PointToScreen(Button1.Location)
                ucDropDown.Location = New Point(pts.X, pts.Y + Button1.Height)
            End If
        End Sub

        Protected Overrides Sub WndProc(ByRef m As Message)
            If m.Msg = &H112 AndAlso m.WParam.ToInt32 = &HF020 AndAlso ucDropDown.Visible Then ucDropDown.Close() 'if the form is minimizing, then close the DropDown
            MyBase.WndProc(m)
        End Sub
    End Class
     

     Here you can see that the DropDown will not close until the (Close Options) button calls the Close method or the form looses focus.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Wednesday, April 11, 2018 6:27 PM Updated 2nd example to fix a bug when form is minimized
    • Proposed as answer by Mr. Monkeyboy Wednesday, April 11, 2018 9:45 PM
    • Marked as answer by ChrisP1980 Thursday, April 26, 2018 9:18 AM
    Wednesday, April 11, 2018 6:03 PM
  •  It is not clear to me if the 'DropDown' is created from in your UserControl or if you want the UserControl as the 'DropDown'.  Either way,  you can add a Panel,  UserControl,  or any other control you want to a new instance of a ToolStripControlHost.  Then you can add that to a new instance of a ToolStripDropDown.  The ToolStripDropDown will do what you want when it is Shown,  it will be on top of all other windows.  You just call one of it's Show method and supply the position you want it shown.

     From there,  it will close when the ToolStripDropDown looses focus,  like if you click elsewhere on the form or screen.  However,  it can also be set up to stay open until you call it's Close method or the Form looses focus.

     For example, here I add a UserControl to a ToolStripControlHost and then add that to a ToolStripDropDown.  I call it's Show method from a Button Click event to show it right below the button.


    If you say it can`t be done then i`ll try it

    Razerz can a menustrip contain controls? I seem to remember where you did something like this with a menu strip and it seems to me that it would lose focus and close if the Form was minimized. Or maybe I'm just remembering things wrong.


    La vida loca

    Wednesday, April 11, 2018 9:49 PM
  • Well unless the user has to select the user control perhaps provide the user control with a ContextMenuStrip.

    This provides the Form with a ContextMenuStrip and when right clicked the ContextMenuStrip displays text and a Button. If the Form is minimized the ContextMenuStrip closes and I suppose it could be launched by some other method. Perhaps then it would not disappear if the Form went out of Focus.

    Option Strict On
    
    Public Class Form1
    
        WithEvents ContextMenuStrip1 As New ContextMenuStrip
        WithEvents BTN1 As New Button
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            ContextMenuStrip1.Items.Add("Get Text")
            With BTN1
                .Size = New Size(120, 40)
                .Text = "Hello Dolly"
                .Name = "BTN1"
            End With
            ContextMenuStrip1.Items.Add(New ToolStripControlHost(BTN1))
            Me.ContextMenuStrip = ContextMenuStrip1
        End Sub
    
    End Class


    La vida loca

    Wednesday, April 11, 2018 10:31 PM
  • Razerz can a menustrip contain controls? I seem to remember where you did something like this with a menu strip and it seems to me that it would lose focus and close if the Form was minimized. Or maybe I'm just remembering things wrong.


    La vida loca

     Yes,  you can add any single control or container control like a Panel or UserControl to a ToolStripControlHost.  Then you can add the ToolStripControlHost to a ToolStripMenu's Items,  a ToolStripDropDown's Items,  or a ContextMenuStrip's Items.

     I don't remember right off hand but,  knowing I have posted examples similar to this before that added one to a ContextMenuStrip, then that example probably did.

     In my first example above,  it will close automatically when it looses focus,  like a ContextMenuStrip normally does.  However,  in my second example where I make it so that it does not close while the form has focus,  it required special handling to close it when the form was minimized.  It seems that the ToolStripDropDown would not close after the form was minimized which I was detecting in the form's LocationChanged event.

     I am sure I could fix that minor problem but,  I had other things I was working on and wanted to wait to see if OP ever came back or maybe had other unmentioned requirements before going any further with it.  There seems to be a lot of questions lately where people ask a question,  we put a lot of effort into a fancy example/answer,  and then they never reply back again or mark an answer.  Getting a little tired of wasting my time on those ones when I could be doing other things.

     PS - I have never seen a crab with nicer work boots than mine.  haha  8)


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Wednesday, April 11, 2018 11:08 PM
    Wednesday, April 11, 2018 11:06 PM
  • LOL. Mr. Land Crab got the boots and pants at the thrift store for $3.50 with military discount!

    O.K. Thanks Razerz. I modified my code so the Button Click event sub sends a mouse event which with the ContextMenuStrip assigned to the Form sends a right down and up so the ContextMenuStrip displays but perhaps not at the correct location or perhaps where the mouses point was. Can't remember. Although right clicking on the actual Form causes it to appear since I assigned it to the Form. But when the Form is minimized it disappears or closes.

    Option Strict On
    
    Public Class Form1
    
        Private Declare Function apimouse_event Lib "user32" Alias "mouse_event" (ByVal dwFlags As Int32, ByVal dX As Int32, ByVal dY As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As Int32) As Boolean
        Const MOUSEEVENTF_RIGHTDOWN As Int32 = &H8
        Const MOUSEEVENTF_RIGHTUP As Int32 = &H10
    
        WithEvents ContextMenuStrip1 As New ContextMenuStrip
        WithEvents BTN1 As New Button
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            ContextMenuStrip1.Items.Add("Get Text")
            With BTN1
                .Size = New Size(120, 40)
                .Text = "Hello Dolly"
                .Name = "BTN1"
            End With
            ContextMenuStrip1.Items.Add(New ToolStripControlHost(BTN1))
            Me.ContextMenuStrip = ContextMenuStrip1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            apimouse_event(MOUSEEVENTF_RIGHTDOWN + MOUSEEVENTF_RIGHTUP, Me.Left + 10, Me.Top + 35, 0, 0)
        End Sub
    
    End Class


    La vida loca

    Thursday, April 12, 2018 12:06 AM