Close Modal Form when mouse click outside form area - c#

I would like to close a modal form when the user clicks outside (anywhere on the computer desktop) the modal form. How can we do this as a modal form is not meant to lose focus.

You need to hook mouse (and keyboard if required) and capture their events. Then check if the click happened outside the form (and area). If yes, flag a sign which can be read by the model form that it can close down.
Algo:
Hook mouse click event.
When callback function is called, check for the click position - if it's inside your form or not (you might need to translate the locations to Desktop locations - I hope you know how to!)
If the point is outside the form, set a flag (boolean or anything that makes you happy). Make sure the form can read the flag somehow.
Trigger an event for form to capture. In it's handler read the flag status. If true, close/unload the form.
This page will tell you technical details and functions.

I don't think you need to make it modal... then you can take siride's option of closing it on the Deactivate event.
The reason you don't need to make it modal: The first time you display it, it will have the focus and be topmost. Modal prevents you from clicking somewhere else, but you want to be able to click somewhere else... and when you do, the form goes away, so there are no modal needs.

Related

How to set focus back to form, after button is pressed

I am making a game, and to open up and close the store, you press S. While in the store, you have six different choices to buy from, but they are all buttons.
However, once you buy something, the focus is no longer on the form, but on the button, and the key down event is part of the form, therefore, because the focus gets switched from the form to the button, the key down event no longer works, and disables you from closing the store and continuing on with the game.
My question is how to set the focus back to a form once a button is press? I started out with visual basic, and the code would be something along the lines of form1.setfocus, but its totally different in c#.
I have tried Activating the form, .focus, a lot, and nothing seems to be setting the focus back to the form. Help would be greatly appreciated.
Form1.focus();
But I think, to get keyboard events on Form itself, you need KeyPreview set to true for the Form so that Form gets Keys first and then other controls.
Try:
form.Focus();
MSDN:
The Focus method returns true if the control successfully received input focus. The control can have the input focus while not displaying any visual cues of having the focus. This behavior is primarily observed by the nonselectable controls listed below, or any controls derived from them.
Tell me more
You can add the key down event to the buttons too.

Alt-Tab notification on panels within a form

I'm trying to clear some variable on a panel, for example, if I had a bool which lets me know when I'm click dragging on a panel's surface I set this to false when a MouseUp event occurs (this may or may not be correct way to do this but serves as an example).
If while click dragging I then alt-tab to another application the panel itself doesn't appear to get any notifications, like focus->leave / mouseup for example, is there something I'm missing, an event I've overlooked?
There seems to be a way of doing this by using the forms Deactivate event, which I suppose I could just call a suspend type method on my panel if I create a new Panel class, but I was wondering if something already existed that would propagate all children on a form with some notification that our form is no longer the main focus.
Reliably getting these kind of notifications requires that you use the Capture property. Set it to true on the MouseDown event. It ensures that all mouse messages are directed to your panel, even if the mouse is no longer hovering the panel. That however still doesn't cover rude focus changes, like Alt+Tab or Alt+Esc. You also need to implement the MouseCaptureChanged event to know when the operating system stepped in.
In general, if you are trying to implement Drag + Drop then you ought to use DoDragDrop(). When it returns you can always be sure that the drag operation is completed, for whatever reason. The return value of the method tells you what happened. Note that this also supports switching to another window, albeit that it is not very discoverable, you drag to the task bar button to force a switch.

How do I make a custom modal popup window in WPF and have it return a value?

I'm taking a whack at WPF and trying to learn as I go. I'd appreciate any advice offered.
I've got a Window that has a Page attached to it (through a Frame on the Window). When you press a button on the Page, I want a custom window to pop up to present several custom options and be displayed in a manner of my choosing (I'm thinking right now I want it to be a grid but that may change as I go on). When selected, the modal window will disappear and return to the calling method (button press from the Page) the value of the selected choice.
I don't want the standard windows dialog box with the options of yes, no, okay, cancel, or anything like that. This is truly just a custom popup that returns a value to the caller when the user makes their selection on the popup.
Create a new Window subclass, which you can layout however you like. Then in your button click event handler, display it modally using myModalWindow.ShowDialog();. You can then have a property on the window class which you can access after it closes in order to access result data, i.e.:
myModalWindow.ShowDialog();
var data = myModalWindow.SomeResultProperty;
If you really want to have something returned from a method, I suppose you could create your own public method on your window class which internally calls ShowDialog() and then returns a value.

Interacting with a form without it activating

I'm trying to implement code-completion popup window in my project. The window is derived from Form. It contains two controls: custom list derived from UserControl (it shows completion possibilities with icons) and a VScrollBar.
When the popup appears, it doesn't steal focus from the editor (form's ShowWithoutActivation is overriden to return true) and the editor sends certain keystrokes to the popup so the user can interact with it using keyboard. So far it works like a charm.
The problem is, I want to allow the user to use mouse as well. But, when the user clicks into the popup window, its form activates and steals focus from the editor. I can react to this by giving the focus back to the editor, I have even set up a Timer to do this regularly, but apart from being a poor solution, the title bar of the editor always flickers when this happens (when the popup is clicked).
Is there any way to interact with the popup form (using mouse) that doesn't make the form activate?
The ShowWithoutActivation's documentation reads: "If your non-activated window needs to use UI controls, you should consider using the ToolStrip controls, such as ToolStripDropDown. These controls are windowless, and will not cause a window to activate when they are selected." This seems exactly like the thing I need, but I want to use a custom control and a scroll bar.
The same problem would be with a tooltip that shows these two arrows to switch method overloads (known from VS) - the whole form would use no controls at all (only render the text and the arrows), but when clicked, it should not activate. The problem could be summarized up to "How to create a form that would never activate, but allow the user to interact with certail controls inside?".
Thanks.
Just override the onFocus event...
public partial class myListBox:ListBox
{
protected override void OnGotFocus(EventArgs e)
{
}
}
The issue is that you're using a Form for this rather than building some custom control that doesn't run in its' own UI thread like a Form does.
The flashing and highlighting is handled by windows whenever a Form activates/focuses. The only thing I cay think of is to make your Form borderless and create/draw/handle your own title bar that doesn't flash when focused.
OK, I may have found a solution. The key seems to be WM_MOUSEACTIVATE message, which the popup form must intercept and respond with MA_NOACTIVATE. But there's a catch - the control derived from UserControl still grabs focus when clicked (the scrollbar luckily doesn't anymore). The problem seems to be in the UserControl.OnMouseDown method, which internally puts focus on the control. There are some ways to fix this:
derive the control from Control instead of UserControl
override the OnMouseDown method and not call base.OnMouseDown there
make the control's CanFocus property return false, but this seems not possible, because that means to make the control either not visible or not enabled, which is both undesirable
The last case when the popup form steals focus seems to be when its resizing (using mouse) ends. But it is safe here to call Owner.Activate() as a result to Activated event...

How to do two things with one click in Windows Form

On my main form, there is another (floatable) window. This floatable window works sort of like a popupwindow in that it will close when the user clicks somewhere else outside of this window. This is handled by the Deactivate event. But what I want to do is, if the user clicks on a different control (say a button), I want to both close this float window and then activate that button with just one click. Currently, the user has to click twice (one to deactivate the window and once more to activate the desired button). Is there a way to do this with just one click?
foreach(Control c in parentForm.Controls)
{
c.Click += delegate(object sender, EventArgs e)
{
if(floatyWindow != null && floatyWindow.IsFloating)
{
floatyWindow.Close();
}
};
}
And then add your handlers as normal. This additional handler can close the floaty window.
Make sure you floaty window isn't a dialog too as this will not allow your parent form's controls to be clicked.
I had a slightly hacky solution. In your Deactivate event, fire another custom event to your main form. Then when you main form is handling the custom event, enumerate through your control(this.Controls) and locate the control under the mouse by checking all their bound then call Focus(). You might need to sort by the one with the smallest surface area, or you can have a separate list of "focus-able" control like button just for this purpose.
Another way might be to switch focus to your main form immediately after OnMouseLeave of the floatable window, or OnMouseHover of your main window, but keep the floatable windows on top, just no focus. Handle the global mouse down of your main form, and close the floatable window by then.
These are just theories, not tested.
I had an issue like this once too, when a customer wanted "floaty" windows all over there application. I used used an approach similar to the one described in this article:
http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/article.asp
Code sample available here:
http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/Popup_Form_Demonstration.asp
By extending this a bit we created "floaty" windows similar to the ones VS uses when you get a runtime error while debugging code.
At the very least reading the code may give you some insight, however, quarrelsome's response may be the more simple solution.

Categories