Cursor.Current vs this.Cursor

Is there any difference between Cursor.Current and this.Cursor (where this is WinForm) in .Net? I always used this.Cursor and I was very lucky, but I recently started using CodeRush and just put some code in the "Wait Cursor" block, and CodeRush used the Cursor.Current property. I saw on the Internet and at work, where other programmers had some problems with the Cursor.Current property. I just wanted to know if there is a difference in the two. Thanks in advance.

I did a little test. I have two winforms. I press the button on form1, set the Cursor.Current property to Cursors.WaitCursor , and then show form2. The cursor does not change in any form. It remains the Cursors.Default cursor (pointer).

If I set this.Cursor to Cursors.WaitCursor in the button click event on form1 and show form2, the wait cursor will only appear on form1, and the default cursor will appear on form2, which is expected. So, I still don't know what Cursor.Current does.

+52
c # winforms cursor
Nov 19 '08 at 17:17
source share
7 answers

Windows sends a window containing the mouse cursor, the WM_SETCURSOR message, giving it the ability to change the shape of the cursor. A control like TextBox uses this by changing the cursor to an I-bar. The Control.Cursor property determines which form will be used.

The Cursor.Current property changes shape directly, without waiting for WM_SETCURSOR response. In most cases, this form is unlikely to last long. As soon as the user moves the mouse, WM_SETCURSOR changes it to Control.Cursor.

The UseWaitCursor property was added in .NET 2.0 to simplify the hourglass display. Unfortunately, this does not work very well. Modifying the form requires the WM_SETCURSOR message, and this will not happen if you set the property to true, and then do something that takes some time. Try this code, for example:

 private void button1_Click(object sender, EventArgs e) { this.UseWaitCursor = true; System.Threading.Thread.Sleep(3000); this.UseWaitCursor = false; } 

The cursor never changes. To drive this into a form, you also need to use Cursor.Current. Here is a small class of helpers to make it easy:

 using System; using System.Windows.Forms; public class HourGlass : IDisposable { public HourGlass() { Enabled = true; } public void Dispose() { Enabled = false; } public static bool Enabled { get { return Application.UseWaitCursor; } set { if (value == Application.UseWaitCursor) return; Application.UseWaitCursor = value; Form f = Form.ActiveForm; if (f != null && f.Handle != IntPtr.Zero) // Send WM_SETCURSOR SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); } } [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); } 

And use it as follows:

 private void button1_Click(object sender, EventArgs e) { using (new HourGlass()) { System.Threading.Thread.Sleep(3000); } } 
+84
Nov 19 '08 at 18:23
source share

I believe that Cursor.Current is the mouse cursor used (no matter where it is on the screen), while this.Cursor is the cursor it will be set to when the mouse passes through your window.

+10
Nov 19 '08 at 17:19
source share

Actually, if you want to use HourGlass from another stream, which will give you a reverse cross-stream exception, because you are trying to access f.Handle from a different stream than the form was originally created. Instead, use the GetForegroundWindow () function instead of user32.dll.

 [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); 

and then

 public static bool Enabled { get { return Application.UseWaitCursor; } set { if (value == Application.UseWaitCursor) { return; } Application.UseWaitCursor = value; var handle = GetForegroundWindow(); SendMessage(handle, 0x20, handle, (IntPtr)1); } } 
+6
Dec 15 '11 at 5:45
source share

this.Cursor is the cursor that will be used when the mouse is over the window that this points to. Cursor.Current - the current mouse cursor, which may differ from this.Cursor if the mouse is in another window.

+5
Nov 19 '08 at 17:20
source share

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()) { //time consuming synchronous task } 

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

+2
Apr 30 '16 at 20:29
source share

This works fine for me when LongRunningOperation () processes messages.

 private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e) { this.Cursor = Cursors.WaitCursor; LongRunningOperation(); this.Cursor = Cursors.Arrow; } 
0
Feb 15 '15 at 3:40
source share

From VB.net VS 2012

 Windows.Forms.Cursor.Current = Cursors.Default 
0
Mar 12 '15 at 19:44
source share



All Articles