Link to home
Start Free TrialLog in
Avatar of BlakeMcKenna
BlakeMcKennaFlag for United States of America

asked on

What event fires when "Normal" ControlBox is clicked on a form?

I need to check when a parent or child form's "normal" controlbox is clicked and I'm not sure which event to check. Is this possible?

Thanks!
Avatar of Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger)
Flag of Canada image

If by "normal" controlbox you mean the little X at the upper right side of the window, the event is FormClosing. But that event can also be called by something else than the Control Box, so if you want to be specific, you need to look at the parameters passed to the event to determine what is causing the Close:
	Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing

		If e.CloseReason = CloseReason.UserClosing Then
			'ControlBox
		Else
			'Something else
		End If

	End Sub

Open in new window

Avatar of BlakeMcKenna

ASKER

Actually it's the Maximize/Minimize button (the middle button) that I'm try to capture.
ASKER CERTIFIED SOLUTION
Avatar of hes
hes
Flag of United States of America image

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
If Blake is on the right track about what you meant "normal" ControlBox, then I need to change my answer.

And sorry to correct Blake, what you meant is more the Restore button. The Maximize and Minimize buttons (plural) are 2 different buttons that appear when the form is neither maximized or minimized. When the form is Maximized, the Maximize button is useless and replaced by a Restore button. However, some might see it as an alternate state of the Maximize button.

Anyway, there is a little problem. This one looks like a simple one, but when you start looking at it carefully, it's not so simple. Maybe someone will have a better idea than mine.

The resizing events (ResizeBegin, Resize and ResizeEnd) can be triggered in different ways:

1. Clicking either the Minimize, Maximize or Restore button.
2. Programmatically changing the Size property of the Form.
3. User resizing the Form by dragging its border.

There is no built-in way that I know to determine which of these 3 triggered the resizing, since these events do not pass any useful parameter.

A moderately complex algorithm could be written, but I started working on it and hit a problem after a few seconds, and do not have time to go further with it right now. So I'm just pushing my thoughts about it in case somebody has the time to work on it.

It would involve, between others, a variable that is incremented on each pass in the Resize event and a Timer that would be created on the first call. After a short while, the timer would look at the variable to determine if the event is called only once or repetitively. If called only once, then we eliminated item 3 in my list of triggers for the event.

The first problem I hit is to find a way to make the difference between a Restore by the user and a resize by the code.

The second one is that in order to know if the unique event call could be triggered as well by a Maximize, a Minimize or a Restore, which brings us back almost to square one. Knowing that the Restore button is available only when the form is Maximized, we would need to keep a constant status of the WindowState in order to know that the Resize started in that state.

There might be other hiccups I did not see.

@hes

Your answer shows your VB6 background, if I am not mislead.

Resize has its use sometimes, but most of the time I see it used in VB.NET, the wrong event was chosen. This probably due to the fact that this was the only resizing event in VB6, and "old hands" are used to it.

The problem is that it triggers many times when the user is resizing a form. In most situations where you want to react to a resizing, you do not need to "follow" the operation, you usually need to react once, either before the resizing begin, most often once the resizing is done. For that purpose the "new" (well, they've been there for 12 years but when you hear of them for the first time, they're kind of new) ResizeBegin and ResizeEnd as most of the time a better choice than Resize.

In your specific example, if the user was resizing manually, the If would be called repetitively without ever being useful, because you cannot minimize a Form while dragging it's border. Sure it would work if the user hit the Minimize button, but would be useless for a manual resize. And in some circumstances, if the code in the If is important, it make the manual resizing very jerky (not sure if it is the right word in English, excuse my French).
Public Class Form1
    Private Const WM_NCLBUTTONDOWN = &HA1
    Private Enum HitTestResult
        HTERROR = (-2)
        HTTRANSPARENT = (-1)
        HTNOWHERE = 0
        HTCLIENT = 1
        HTCAPTION = 2
        HTSYSMENU = 3
        HTGROWBOX = 4
        HTMENU = 5
        HTHSCROLL = 6
        HTVSCROLL = 7
        HTMINBUTTON = 8
        HTREDUCE = HTMINBUTTON
        HTMAXBUTTON = 9
        HTZOOM = HTMAXBUTTON
        HTLEFT = 10
        HTRIGHT = 11
        HTTOP = 12
        HTTOPLEFT = 13
        HTTOPRIGHT = 14
        HTBOTTOM = 15
        HTBOTTOMLEFT = 16
        HTBOTTOMRIGHT = 17
        HTBORDER = 18
        HTOBJECT = 19
        HTCLOSE = 20
        HTHELP = 21
    End Enum

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = WM_NCLBUTTONDOWN Then
            Call ControlBoxClicked(m)
        End If
        MyBase.WndProc(m)
    End Sub

    Private Sub ControlBoxClicked(ByVal m As System.Windows.Forms.Message)
        Dim hitTest As HitTestResult = m.WParam
        Select Case hitTest
            Case HitTestResult.HTMINBUTTON
                Debug.Print("Min button down")
            Case HitTestResult.HTMAXBUTTON
                If Me.WindowState = FormWindowState.Maximized Then
                    Debug.Print("Restore button down")
                Else
                    Debug.Print("Max button down")
                End If
            Case HitTestResult.HTCLOSE
                Debug.Print("Close button down")
        End Select
    End Sub
End Class

Open in new window

<< if I am not mislead.>> Yes you are
Hes,

You were the closest. I actually put the code in the Resize() event. Looks like this.

    Private Sub frmMain_Resize(sender As Object, e As EventArgs) Handles Me.Resize
        If Me.WindowState = FormWindowState.Normal Then
            ResizeMDIParent(Me)
        End If
    End Sub

Open in new window


Wow, I don't why I made this so hard.

Thanks for the help guys!