• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 237
  • Last Modified:

User Control issue

I’m fairly certain that this is NOT what the person who told me to use a UserControl for this had in mind, but I couldn’t figure out how to reference other controls on the main form from the user control.
 
SOOO
In my windows forms project, I have a frmMain.  
On that I have placed a user control that consists of 12 buttons. It’s a number pad.  0 – 9, a decimal point and a clear button.
The code below all works fine…. With one exception.
I cannot figure out how to “Hide” the user Control again.  At least not consistently.

I have the pnlData_Click function below, and set that to fire when the background panel on the main form is clicked, but that is not always done because there are multiple other controls on the main form that can be clicked instead.  I have also tried to add an event for when the usercontrol loses focus also... its not working.

Any ideas?


In the frmMain I have the following code.
    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        AddHandler UcNumPad1.btn0.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn1.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn2.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn3.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn4.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn5.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn6.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn7.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn8.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btn9.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btnClear.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.btnDec.Click, AddressOf UcNumPad1_Click
        AddHandler UcNumPad1.VisibleChanged, AddressOf UcNumPad1_VisibleChanged
        AddHandler UcNumPad1.Leave, AddressOf UcNumPad1_VisibleChanged
    End Sub

    Private Sub txtItemQty_Enter(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Try
            Dim temTextBox As New TextBox
            temTextBox = sender
            _CurrentTextBox = sender.Name
            pnlData.Controls.Add(UcNumPad1)
            UcNumPad1.Location = New System.Drawing.Point(280, temTextBox.Location.Y + 20)
            UcNumPad1.BringToFront()
            UcNumPad1.Visible = True
            UcNumPad1.Focus()

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
    Private Sub UcNumPad1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim txtTextBox() As Control = pnlData.Controls.Find(_CurrentTextBox, True)
        Select Case sender.name
            Case "btnClear"
                txtTextBox(0).Text = ""
            Case "btn1"
                txtTextBox(0).Text = txtTextBox(0).Text & "1"
            Case "btn2"
                txtTextBox(0).Text = txtTextBox(0).Text & "2"
            Case "btn3"
                txtTextBox(0).Text = txtTextBox(0).Text & "3"
            Case "btn4"
                txtTextBox(0).Text = txtTextBox(0).Text & "4"
            Case "btn5"
                txtTextBox(0).Text = txtTextBox(0).Text & "5"
            Case "btn6"
                txtTextBox(0).Text = txtTextBox(0).Text & "6"
            Case "btn7"
                txtTextBox(0).Text = txtTextBox(0).Text & "7"
            Case "btn8"
                txtTextBox(0).Text = txtTextBox(0).Text & "8"
            Case "btn9"
                txtTextBox(0).Text = txtTextBox(0).Text & "9"
            Case "btn0"
                txtTextBox(0).Text = txtTextBox(0).Text & "0"
            Case "btnDec"
                txtTextBox(0).Text = txtTextBox(0).Text & "."
        End Select
    End Sub

    Private Sub UcNumPad1_VisibleChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        If Visible = True Then
            Dim txtTextBox() As Control = pnlData.Controls.Find(_CurrentTextBox, True)
            txtTextBox(0).BackColor = Color.Plum
        Else
            Dim txtTextBox() As Control = pnlData.Controls.Find(_CurrentTextBox, True)
            txtTextBox(0).BackColor = Color.White
        End If
    End Sub

    Private Sub pnlData_Click(sender As System.Object, e As System.EventArgs) Handles pnlData.Click, Panel1.Click
        UcNumPad1.Visible = False
    End Sub

Open in new window

0
ScottParker
Asked:
ScottParker
  • 5
  • 4
  • 3
  • +1
2 Solutions
 
CrashmanCommented:
you can try use the lost focus event
0
 
ScottParkerAuthor Commented:
I already tried to add an event for when the usercontrol loses focus.  No luck.
I think its because the buttons on the user control itself is what has focus.
0
 
CrashmanCommented:
Could you post a example, to work with it
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Here is more what I meant:
Public Class Form1

    Private _CurrentTextBox As TextBox = Nothing

    Private Sub TB_GotFocus(sender As Object, e As System.EventArgs) Handles TextBox1.GotFocus, TextBox2.GotFocus, TextBox3.GotFocus
        _CurrentTextBox = sender
    End Sub

    Private Sub UcNumPad1_Clear() Handles UcNumPad1.Clear
        If Not IsNothing(_CurrentTextBox) Then
            _CurrentTextBox.Clear()
        End If
    End Sub

    Private Sub UcNumPad1_Character(value As String) Handles UcNumPad1.Character
        If Not IsNothing(_CurrentTextBox) Then
            _CurrentTextBox.SelectedText = value
        End If
    End Sub

End Class

Open in new window


Public Class UcNumPad

    Public Event Clear()
    Public Event Character(ByVal value As String)

    Private Sub btn_Click(sender As Object, e As System.EventArgs) Handles _
        btn0.Click, btn1.Click, btn2.Click, btn3.Click, btn4.Click, btn5.Click, _
        btn6.Click, btn7.Click, btn8.Click, btn9.Click, btnDec.Click, btnClear.Click

        If sender Is btnClear Then
            RaiseEvent Clear()
        Else
            RaiseEvent Character(DirectCast(sender, Button).Text)
        End If
    End Sub

End Class

Open in new window

0
 
PaulHewsCommented:
If you have a look at MSDN LostFocus documentation you will see that Microsoft recommends using Enter and Leave events rather than GotFocus and LostFocus.
0
 
CrashmanCommented:
the event is fired when you click another part of the form or not?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Here's one way to make the NumPad disappear when you click outside of it:
Public Class UcNumPad

    Public Event Clear()
    Public Event Character(ByVal value As String)

    Private WithEvents _MyFilter As MyFilter

    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        _MyFilter = New MyFilter
        Application.AddMessageFilter(_MyFilter)
    End Sub

    Private Sub btn_Click(sender As Object, e As System.EventArgs) Handles _
        btn0.Click, btn1.Click, btn2.Click, btn3.Click, btn4.Click, btn5.Click, _
        btn6.Click, btn7.Click, btn8.Click, btn9.Click, btnDec.Click, btnClear.Click

        If sender Is btnClear Then
            RaiseEvent Clear()
        Else
            RaiseEvent Character(DirectCast(sender, Button).Text)
        End If
    End Sub

    Private Sub _MyFilter_MouseDown() Handles _MyFilter.MouseDown
        If Me.Visible Then
            Dim RC As Rectangle = Me.RectangleToScreen(Me.ClientRectangle)
            If Not RC.Contains(Cursor.Position) Then
                Me.Visible = False
            End If
        End If
    End Sub

    Private Class MyFilter
        Implements IMessageFilter

        Public Event MouseDown()

        Private Const WM_LBUTTONDOWN As Integer = &H201

        Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
            Select Case m.Msg
                Case WM_LBUTTONDOWN
                    RaiseEvent MouseDown()

            End Select
            Return False
        End Function

    End Class

End Class

Open in new window

0
 
ScottParkerAuthor Commented:
Idle_Mind

Ok, that code does make more sense now.
The only thing I think its missing is how to "Show" and "Hide" the user control.

I assume to show it, I would just add the visible = true command to the TB_GotFocus function you mentioned.   I can also put the location code there.. i.e. where on the screen I want the user control to show up.

But when the user is done, and touches (touch screen monitor) another part of the screen how do I make the user control "Hide" again.

edit( you posted while I was typing this)

Crashman,
yes the event is fired when another part of the form is clicked.. UNLESS the point of the click hapens to be on top of another control that is on the form.  That is what makes this so ugly.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Exactly...just set the Visible() property to True and make its Location() property what you want.

The second post I made makes the NumPad automatically hide itself when the user clicks (or touches) somewhere outside the control.  This magic is accomplished using IMessageFilter to trap the WM_LBUTTONDOWN message and then compare the current screen coords to that of the UserControl.
0
 
ScottParkerAuthor Commented:
Thank you once again.  Your code worked perfectly.  I even kind of understand it now.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
"I even kind of understand it now."

That's the best part.  =)

Do you still have any questions about the code that I can answer?
0
 
ScottParkerAuthor Commented:
No, I think I got the idea now...

I added
AddHandler UcNumPad1.VisibleChanged, AddressOf UcNumPad1_VisibleChanged

to the main form so that way I could change the background color of the _CurrentTextBox.

I also looked at the _MyFilter_MouseDown() and noticed how you picked a rectangle that is where the user control is, and if the mouse is outside of that rectangle, then turn the visible to false.  

I don't pretend to understand exactly how the MyFilter class works, but it does so for now I am happy.

All in all in the last 2 days I learned a lot about User Controls and have decided to now add another one to this project to handle a different issue.

Thanks again
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
IMessageFilter allows your application to trap and filter windows messages before they get dispatched to the current form/control.  It's a low level technique that doesn't need to be used very often, as a solution can usually be derived by overriding WndProc() for a specific form/control.  In this case, though, we needed to know when the mouse was clicked anywhere on the form so I needed a common area outside any specific form/control; IMessageFilter fits the bill perfectly for this situation.
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 5
  • 4
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now