WinForms form partially loses focus after disabling all controls - winforms

The focus rectangle and textbox caret are lost after disabling all controls, then enabling them again (vs2012 / .NET Framework v4.5).
To reproduce the issue, just create a WinForms application project, add a button and a textbox in the form, then use this code to disable and enable both controls in the button click event:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.Enabled = false;
button1.Enabled = true;
textBox1.Enabled = true;
}
You may cycle between the textbox and the button using Tab/Shift+Tab as expected, until you press the button.
After that, the focus is partially lost (its weird). You can still use Tab/Shift+Tab and arrows to nagivate between the controls, and press Enter to active the button, but you cannot type in the textbox, nor use the space key to press the button. The textbox caret and the button focus rectangle are not displayed anymore. Changing focus to another application then returning to this form will fix the focus issue.
This issue does not happen if you don't disabled at least one control that is able to receive focus. Also the focus behavior is restored by disabling and enabling again the form, like this:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.Enabled = false;
button1.Enabled = true;
textBox1.Enabled = true;
this.Enabled = false;
this.Enabled = true;
}
I was trying to disable all the controls of a more complex form at the start of a task, so the task would enable again all controls after finishing, to prevent user input during the processing, but without locking the UI thread. I thought it was related to the cross-thread invoke calls, but I found this issue happens even with all code running on UI thread.

This undesired behavior can be fixed by calling the form Focus() method:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.Enabled = false;
button1.Enabled = true;
textBox1.Enabled = true;
this.Focus();
}
The ActiveControl is not changed after calling Focus(), so this works very well for me.

Related

Winforms ContextMenuStrip wont open when Opening event is handled

I'm moving a Winforms app from VB to C#. I have a TrueDBGrid with a ContextMenuStrip thats pops up on a right click. When I don't handle the mnuContext Opening event the menu pops up. When I do handle the event the handler is called but the menu wont popup - even if the handler does nothing.
The code below has been trimmed to just have the handler call, so it's not what the code is doing, just the existence of the handler itself.
public void MenuOpeningHandler(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = false;
}
Setup code is:
public InvoiceListForm()
{
InitializeComponent();
mnuContext.Opening += MnuContext_Opening;
}
private void MnuContext_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
MenuOpeningHandler(sender, e);
e.Cancel = false;
}
The event appears to be stopped/Cancelled instead of continuing to propagate and open. Any idea what could be missing?

Closing a Windows Form, using the Close Window button, when a Validation Message is showing

I have a Windows form that has a validation event on a textBox so that if the value of that TextBox is a value that already exists it triggers a validation error.
private void txtUsername_Validating(object sender, CancelEventArgs e)
{
var alreadyExists = _logic.UserIdExists(txtUsername.Text.Trim());
if(alreadyExists)
{
errorProvider1.SetError(txtUsername, "This Userid already exists, please choose an alternative");
e.Cancel = true;
}
}
private void txtUsername_Validated(object sender, EventArgs e)
{
errorProvider1.SetError(txtUsername, "");
}
this.txtUsername.Validating += new System.ComponentModel.CancelEventHandler(this.txtUsername_Validating);
this.txtUsername.Validated += new System.EventHandler(this.txtUsername_Validated);
This results in an error image appearing next to that textBox along with a tooltip error message.
If I try and close the application, using the Close button at the top of the window, at this time I cannot as the above Event keeps firing even when I try and close the window (due to me taking focus away from the Text box).
Is there a way of closing the window, without resorting to creating an additional Close button on the form?
Based on your description, you want to maintain the default auto-validation behavior yet allow the Form to be closed using the title bar close button. I have observed that the Form.Closing event is raised in such a circumstance, however its argument Cancel property is preset to true. A simple solution is to handle this event and set e.Cancel = false. Implement any logic in the handler that you deem necessary.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing) e.Cancel = false;
}

WPF Mousedown => No MouseLeave Event

I'm building a Windows Presentation Foundation control with Microsoft Blend.
When I leave my control by pressing the left-mouse-button, the MouseLeave-Event is not raised. Why not?
This is intended behaviour: When you are doing mousedown on a control and leaving the control, the control STILL retains its "capture" on the mouse, meaning the control won't fire the MouseLeave-Event. The Mouse-Leave Event instead will be fired, once the Mousebutton is released outside of the control.
To avoid this, you can simple tell your control NOT to capture the mouse at all:
private void ControlMouseDown(System.Object sender, System.Windows.Forms.MouseEventArgs e)
{
Control control = (Control) sender;
control.Capture = false; //release capture.
}
Now the MouseLeave Event will be fired even when moving out while a button is pressed.
If you need the Capture INSIDE the Control, you need to put in more effort:
Start tracking the mouseposition manually, when the mousekey is pressed
Compare the position with the Top, Left and Size Attributes of the control in question.
Decide whether you need to stop the control capturing your mouse or not.
public partial class Form1 : Form
{
private Point point;
private Boolean myCapture = false;
public Form1()
{
InitializeComponent();
}
private void button1_MouseDown(object sender, MouseEventArgs e)
{
myCapture = true;
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (myCapture)
{
point = Cursor.Position;
if (!(point.X > button1.Left && point.X < button1.Left + button1.Size.Width && point.Y > button1.Top && point.Y < button1.Top + button1.Size.Height))
{
button1.Capture = false; //this will release the capture and trigger the MouseLeave event immediately.
myCapture = false;
}
}
}
private void button1_MouseLeave(object sender, EventArgs e)
{
MessageBox.Show("Mouse leaving");
}
}
of course you need to stop the own tracking ( myCapture=false;) on MouseUp. Forgot that one :)
When I don't get mouse events I expect I typically use Snoop to help me understand what is happening.
Here are a couple of links:
1- Snoop (a WPF utility)
2- CodePlex project for Snoop
And for completeness and historical reasons (not the bounty - it doesn't make sense having two duplicate questions - you should probably move it into one if not too late)...
I made a thorough solution using global mouse hook here (approach 2)
WPF: mouse leave event doesn't trigger with mouse down
And simplified its use - you can use it by binding to commands in your view-model - e.g.
my:Hooks.EnterCommand="{Binding EnterCommand}"
my:Hooks.LeaveCommand="{Binding LeaveCommand}"
my:Hooks.MouseMoveCommand="{Binding MoveCommand}"
...more details in there
Old question but I came across the same problem with a Button (MouseLeave does not fire while MouseDown because MouseDown Captures the Mouse...)
This is how I solved it anyway:
element.GotMouseCapture += element_MouseCaptured;
static void element_MouseCaptured(object sender, MouseEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
element.ReleaseMouseCapture();
}
Hope that helps someone looking for a quick fix :P

Loss of Silverlight mouse up events after mouse capture?

I created a very simple test control that has a Rectangle on a canvas (within other containers, but inconsequential). The Rectangle has event handlers for mouse down, mouse move, and mouse up. If I capture the mouse in the Rectangle's MouseLeftButtonDown event, I do not receive a corresponding MouseLeftButtonUp event.
Some code:
private void rect1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (_captured = CaptureMouse())
{
_offset = new Point(Canvas.GetLeft(rect1), Canvas.GetTop(rect1));
_origin = e.GetPosition(RootCanvas);
e.Handled = true;
}
}
private void rect1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_captured)
{
ReleaseMouseCapture();
_captured = false;
e.Handled = true;
}
}
I attached event handlers for the container elements as well, just to make sure one of them wasn't getting the mouse-up event somehow, but none of them were. Is there an expectation of this in Silverlight that I haven't yet learned?
I think you are little confused about what is actually capturing the mouse events.
Consider when you do this:-
if (_captured = CaptureMouse())
what object is the CaptureMouse actually being called against?
Answer: The user control for which your code is the code-behind. Had you wanted the rectangle to capture the mouse you would do:-
if (_captured = rect1.CaptureMouse())
CaptureMouse(); from mouseDown Event and then try.

Winforms - why does a "Show()" after a system tray double click end up in my app minimized?

Winforms - why does a "Show()" after a system tray double click end up in my app minimized?
How do I ensure Inthe notifyicon double click event that my hidden main form comes back visible as normal, not minimized (nor maximised for that matter too)
I would guess that you put your application in tray on minimize action. In that case, Show just restores visibility.
Try adding form.WindowState = Normal before Show().
Hiding your form with the NotifyIcon is often desirable so your app starts in the tray right away. You can prevent it from getting visible by overriding the SetVisibleCore() method. You also typically want to prevent it from closing when the user clicks the X button, override the OnFormClosing method to hide the form. You'll want a context menu to allow the user to really quit your app.
Add a NotifyIcon and a ContextMenuStrip to your form. Give the CMS the Show and Exit menu commands. Make the form code look like this:
public partial class Form1 : Form {
bool mAllowClose;
public Form1() {
InitializeComponent();
notifyIcon1.DoubleClick += notifyIcon1_DoubleClick;
notifyIcon1.ContextMenuStrip = contextMenuStrip1;
showToolStripMenuItem.Click += notifyIcon1_DoubleClick;
exitToolStripMenuItem.Click += (o, e) => { mAllowClose = true; Close(); };
}
protected override void SetVisibleCore(bool value) {
// Prevent form getting visible when started
// Beware that the Load event won't run until it becomes visible
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
protected override void OnFormClosing(FormClosingEventArgs e) {
if (!this.mAllowClose) { // Just hide, unless the user used the ContextMenuStrip
e.Cancel = true;
this.Hide();
}
}
void notifyIcon1_DoubleClick(object sender, EventArgs e) {
this.WindowState = FormWindowState.Normal; // Just in case...
this.Show();
}
}

Resources