I noticed an interesting thing about setting up cursors, so I would like to clarify some of the misunderstandings that I had before, and I hope this can help others:
When trying to set the form cursor with
this.cursor = Cursors.Waitcursor
you are actually setting the cursor for the control, not the entire form, because the cursor is a property of the Control class.
Also, the cursor will only be changed to this cursor when the mouse is actually over the actual control (obviously the shape area)
As Hans Passant said,
Windows sends a window containing the mouse cursor, Message WM_SETCURSOR, giving the opportunity to change the cursor form
I don’t know if windows will send messages directly to the controls or if the form passes these messages to it child controls based on the position of the mouse, I most likely guess the first method, because when I received messages with the WndProc override of the form control, when I was above the text box, for example, the form did not process any messages. (please, someone gives clarity on this)
Basically, my suggestion would be to live off this. Cursor and stick to this.usewaitcursor, since this changes the cursor property to waitcursor for all child controls.
The problem with this is also the same as at the Application.usewaitcursor application level, while you are not above the form / forms with your cursor, no WM_SETCURSOR message is sent by windows, so if you start a lengthy synchronous operation before moving the mouse over the area forms a form can only process such a message when a lengthy synchronous operation ends.
(I would not suggest running a lot of time in the UI thread at all, basically this is what causes the problem here)
I slightly improved Hans Passan's answer, so you can set the hourglass either at the application level or at the form level, and also avoid InvalidOperationException from cross-thread calls:
using System; using System.Windows.Forms; public class HourGlass : IDisposable { public static bool ApplicationEnabled { get{ return Application.UseWaitCursor; } set { Form activeFrom = Form.ActiveForm; if (activeFrom == null || ApplicationEnabled == value) return; if (ApplicationEnabled == value)return; Application.UseWaitCursor = (bool)value; if (activeFrom.InvokeRequired) { activeFrom.BeginInvoke(new Action(() => { if (activeFrom.Handle != IntPtr.Zero) SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR })); } else { if (activeFrom.Handle != IntPtr.Zero) SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR } } } private Form f; public HourGlass() { this.f = Form.ActiveForm; if (f == null) { throw new ArgumentException(); } Enabled = true; } public HourGlass(bool enabled) { this.f = Form.ActiveForm; if (f == null) { throw new ArgumentException(); } Enabled = enabled; } public HourGlass(Form f, bool enabled) { this.f = f; if (f == null) { throw new ArgumentException(); } Enabled = enabled; } public HourGlass(Form f) { this.f = f; if (f == null) { throw new ArgumentException(); } Enabled = true; } public void Dispose() { Enabled = false; } public bool Enabled { get { return f.UseWaitCursor; } set { if (f == null || Enabled == value) return; if (Application.UseWaitCursor == true && value == false) return; f.UseWaitCursor = (bool)value; if(f.InvokeRequired) { f.BeginInvoke(new Action(()=> { if (f.Handle != IntPtr.Zero) SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR })); } else { if (f.Handle != IntPtr.Zero) SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR } } } [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); }
To use it at the application level:
try { HourGlass.ApplicationEnabled = true; //time consuming synchronous task } finally { HourGlass.ApplicationEnabled = false; }
For use at the form level, you can either use the current active form:
using (new HourGlass()) {
or you can initialize a local variable in the form:
public readonly HourGlass hourglass; public Form1() { InitializeComponent(); hourglass = new HourGlass(this, false); }
and use it later in the finally catch try block