How do I close a form when a user clicks outside the form's window?
Solution 1
With thanks to p-daddy in this question, I've found this solution which allows me to use ShowDialog:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
this.Capture = true;
}
protected override void OnCaptureChanged(EventArgs e)
{
if (!this.Capture)
{
if (!this.RectangleToScreen(this.DisplayRectangle).Contains(Cursor.Position))
{
this.Close();
}
else
{
this.Capture = true;
}
}
base.OnCaptureChanged(e);
}
Solution 2
In your form's Deactivate event, put "this.Close()". Your form will close as soon as you click anywhere else in Windows.
Update: I think what you have right now is a Volume button, and inside the Click event you create an instance of your VolumeSlider form and make it appear by calling ShowDialog() which blocks until the user closes the popped-up form. In the next line you read the volume the user selected and use it in your program.
This is OK, but as you've noticed it forces the user to explicitly close the popup in order to get back to the main program. Show() is the method you really want to use here on your popup form, but Show() doesn't block which means the Click event back on your main form finishes without knowing what the new volume is supposed to be.
A simple solution is to create a public method on your main form like this:
public void SetVolume(int volume)
{
// do something with the volume - whatever you did before with it
}
Then, in your Volume button's Click event (also on the main form), you make the VolumeSlider appear like so:
VolumeSlider slider = new VolumeSlider();
slider.Show(this); // the "this" is needed for the next step
In the VolumeSlider form, as the user works the (I guess) scrollbar, you put this code in the scrollbar's ValueChanged event (I think that's what it is):
MainForm owner = (MainForm)this.Owner;
owner.SetVolume(scrollbar.Value);
And then in the VolumeSlider form's Deactivate event you would put this.Close() as mentioned above. Your form will then behave as expected.
Solution 3
With Simon's solution I had the same Problem describt by Noam. With following code I've avoid the "Click through" problem...
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// if click outside dialog -> Close Dlg
if (m.Msg == NativeConstants.WM_NCACTIVATE) //0x86
{
if (this.Visible)
{
if (!this.RectangleToScreen(this.DisplayRectangle).Contains(Cursor.Position))
this.Close();
}
}
}
Solution 4
You should use Deactivate:
I have a form called Form2.
In the Deactivate section of the Properties window.
You declare the name Form2_Deactivate.
In the Form2.cs file:
private void Form2_Deactivate(object sender, EventArgs e)
{
this.Close();
}
Simon
Updated on June 29, 2022Comments
-
Simon almost 2 years
I want to close a System.Windows.Forms.Form if the user clicks anywhere outside it. I've tried using IMessageFilter, but even then none of the messages are passed to PreFilterMessage. How do I receive clicks outside a form's window?
-
Simon over 15 yearsit's a volume slider - that seems to be the way everyone else has implemented them.
-
MusiGenesis over 15 yearsThis isn't too different from a drop-down box - the choice list goes away as soon as you click somewhere else.
-
MusiGenesis over 15 yearsMe: "Doctor, it hurts when I do this." Doctor: "Don't do that." See my updates above in a second.
-
MusiGenesis over 15 yearsLet me know if it works for you. I hate to be snarky and wrong at the same time. :)
-
Noam Gal over 14 yearsThanks. Just what I was looking for.
-
Noam Gal over 14 yearsmm... It's not working as expected after all - when the form loads, I have the "hand" mouse cursor, and any click outside the form closes it. If I want to interact with the form itself, the first click only seems to clear the "Capture", and does not register inside the form (clicking on a checkbox does not check it, for example), and afterwards clicking outside does not close the window. Is there some other way to do this?
-
Simon over 14 years@Noam: how simple is your form? If it's just got one child, you could set the child's capture rather than the form's.
-
Ashraf Bashir about 12 yearsIt's OnMouseCaptureChanged not OnCaptureChanged
-
Andrew Barber almost 12 yearsCould you provide some context on this answer to enable someone to use it properly?
-
MusiGenesis about 11 years@JesonPark: sure it does: msdn.microsoft.com/en-us/library/…
-
AminM about 11 yearstnx MusiGenesis i find it!
-
Bitterblue almost 10 yearsThis is the truly correct answer. When you click outside of a form that was opened with
ShowDialog()
, 3 messages are sent:WM_NCACTIVATE
,WM_ACTIVATE
andWM_ACTIVATEAPP
. Don't use the 3rd one but the 2nd (WM_ACTIVATE
) might be even better than the 1st one. Also don't forget to setDialogResult
! -
Pablo Jomer over 9 yearsI used OnVisibleChanged and OnMouseCaptreChanged and it works but some times the mouse is hidden.
-
Patapom about 2 yearsThis is what worked for me! Other solutions are just clunky, especially the one using OnDeactivate() that makes my entire application give focus to an entirely other application when closing the child form, for some reason (??)...