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.
Related
I'm after some opinions / advice as I'm rather new to event-driven programming and C# having come from web development origins.
I'm currently making a program in C# / Winforms, with a series of SplitContainer controls on the main form. I want to allow the user to effectively be able to select a group of them, say any 3 out of 8 (not limited to that). To start selecting them, the user will click a button and the program will go into a selecting mode, and at that time, if the user clicks on a control, the color of it will change indicating that it is selected.
At this stage, I have made it work fine, but I feel it's not very efficient in its detection of MouseMove events. I've bound a MouseMove event to the SplitContainer, and inside that event, the program detects whether we're in selecting mode. If so, and the user clicks, change the color. If not in selecting mode, then it wont do anything.
My worry is that every time the user moves their cursor over the control, this event is fired and it detects whether selecting mode is enabled. I feel like this should be the other way around, that is; only in selecting mode is such an event even listened to.
Here are some cut-outs to explain what I've got at the moment.
public bool selectingMode = false;
public Form(){
SplitContainer split = new SplitContainer();
split.MouseMove += new MouseEventHandler(MouseMoved);
this.Controls.Add(split);
}
void MouseMoved(object sender, MouseEventArgs e){
if(selectingMode){
//change color of split
}
}
As mentioned, that MouseMoved() method is triggered every time the user moves their cursor over that control, and then it only actions something if it's in selectingMode. Is there any way to reverse this? Only trigger that event if in selectingMode?
If I'm worrying about something that doesn't really matter, are you able to explain why? It seems like poor practice and that it would be using system resources (however little), especially considering that the vast majority of the time using this program will be spent with the cursor inside this box.
I appreciate and input, thanks!
Sean
Implement the selectingMode as property and put in the setter a split.MouseMove += new MouseEventHandler(MouseMoved); or split.MouseMove -= new MouseEventHandler(MouseMoved); depending on true or false.
Besides I don't think this change is necessary for performance reasons.
You may want to use a different event that satisfies your condition:
SplitContainer Class: MSDN
SplitContainer Event: OnMouseClick
try subscribing to that event if you want it to be fired on click only, also, if you want to unsubscribe to an event, use the -= tag.
The WinRT TextBox control has a delete button that shows up when the control has focus and there is text in it.
When the control loses focus by tapping outside of it or tabbing outside of it, the delete button disappears.
When the control loses focus by tapping in a different app (two apps are up in splitscreen), the delete button doesn't disappear.
Is there a way to detect the different lost focus events? Nothing from the sender or RoutedEventArgs is different in the two cases where the control loses focus.
You can handle Window.Activated to check if the whole app has lost focus:
This event occurs when a Window has been activated or deactivated by
the system. An app can determine what the status of the Window
activation is by checking the
WindowActivatedEventArgs.WindowActivationState property. A Window
could be visible on screen but not be active (for example, in snapped
apps). Additionally, if any other parts of the system takes focus away
from the window, this event will occur. This could happen as a result
of user interaction or code, and the WindowActivationState will
indicate which action has taken place.
http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.window.activated.aspx
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.
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...
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.