tags:

views:

1102

answers:

4

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?

A: 

If it is a child form in an MDI application, you could trap the click in the parent form, otherwise the solution will be messy.

I am not convinced what you suggest represents intuitive UI behaviour anyway. Are you sure that is the best design?

Galwegian
it's a volume slider - that seems to be the way everyone else has implemented them.
Simon
This isn't too different from a drop-down box - the choice list goes away as soon as you click somewhere else.
MusiGenesis
+4  A: 

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.

MusiGenesis
Unfortunately this doesn't work with ShowDialog()
Simon
Me: "Doctor, it hurts when I do this." Doctor: "Don't do that." See my updates above in a second.
MusiGenesis
Let me know if it works for you. I hate to be snarky and wrong at the same time. :)
MusiGenesis
A: 

If you are trying to make a popup window that behaves a little bit like a menu, except that it lets you interact with your controls, you could try hosting a usercontrol inside a toolstrip dropdown.

+1  A: 

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);
}
Simon
Thanks. Just what I was looking for.
Noam Gal
mm... 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?
Noam Gal
@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.
Simon