[ACCEPTED]-Cursor.Current vs. this.Cursor-cursor.current
Windows sends the window that contains the 22 mouse cursor the WM_SETCURSOR message, giving 21 it an opportunity to change the cursor shape. A 20 control like TextBox takes advantage of 19 that, changing the cursor into a I-bar. The 18 Control.Cursor property determines what 17 shape will be used.
The Cursor.Current property 16 changes the shape directly, without waiting 15 for a WM_SETCURSOR response. In most cases, that 14 shape is unlikely to survive for long. As 13 soon as the user moves the mouse, WM_SETCURSOR 12 changes it back to Control.Cursor.
The UseWaitCursor 11 property was added in .NET 2.0 to make it 10 easier to display an hourglass. Unfortunately, it 9 doesn't work very well. It requires a WM_SETCURSOR 8 message to change the shape and that won't 7 happen when you set the property to true 6 and then do something that takes a while. Try 5 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 4 whack that into shape, you'll need to use 3 Cursor.Current as well. Here is a little 2 helper class 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 1 like this:
private void button1_Click(object sender, EventArgs e) {
using (new HourGlass()) {
System.Threading.Thread.Sleep(3000);
}
}
I believe that Cursor.Current is the mouse 4 cursor currently being used (regardless 3 of where it is on the screen), while this.Cursor 2 is the cursor it will be set to, when the 1 mouse passes over your window.
this.Cursor
is the cursor that will be used when the 4 mouse is over the window referred to by 3 this
. Cursor.Current
is the current mouse cursor, which might 2 be different from this.Cursor
if the mouse is over 1 a different window.
Actually if you would like to use HourGlass 6 from another thread that will give you back 5 cross-threading exception because you are 4 trying to access f.Handle from different 3 thread than form was originally created. Use 2 GetForegroundWindow() instead from user32.dll.
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
and 1 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);
}
}
I have noticed an interesting thing about 49 setting cursors, so I would like to clear 48 some misunderstandings that I myself had 47 before and I hope it may help others too:
When 46 you try to set a form's cursor by using
this.cursor 45 = Cursors.Waitcursor
you actually set the 44 cursor for the control and not the whole 43 form since cursor is property of the Control 42 class.
Also of course the cursor will only 41 be changed to the given cursor when the 40 mouse is actually over the actual control 39 (explicitly the form's area)
As Hans Passant 38 has already stated that:
Windows sends the 37 window that contains the mouse cursor the WM_SETCURSOR 36 message, giving it an opportunity to change 35 the cursor shape
I don't know if windows 34 sends messages directly to controls or if 33 the form relays those messages to it's child 32 controls based on mouse position, I'd most 31 likely guess on the first method since when 30 i fetched the messages with overriding WndProc 29 of the form control, when i was over the 28 textbox for example, the form didn't process 27 any messages. (please someone give clarity 26 on this)
Basically my suggestion would be 25 to reside from using this.cursor also and 24 stick to this.usewaitcursor, since that 23 changes the cursor property to waitcursor 22 for all child controls.
The problem with 21 this is also the same as with the application 20 level Application.usewaitcursor, while you 19 are not over the form/forms with your cursor 18 no WM_SETCURSOR message is being sent by 17 windows, so if you start a time consuming 16 synchronous operation before moving your 15 mouse over the form's area, the form can 14 only process such message when the time 13 consuming synchronous operation finishes.
(I 12 would not suggest running time consuming 11 tasks in the UI thread at all, mainly this 10 is what is causing the issue here)
I made 9 a little improvement on Hans Passant's answer, so 8 the hourglass can be either set on application 7 level or form level, also avoiding InvalidOperationException 6 from cross threaded operation 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 5 it on application level:
try
{
HourGlass.ApplicationEnabled = true;
//time consuming synchronous task
}
finally
{
HourGlass.ApplicationEnabled = false;
}
For using it on 4 form level you can either use for the current 3 active form:
using (new HourGlass())
{
//time consuming synchronous task
}
or you can initialize a local 2 variable in the form like this:
public readonly HourGlass hourglass;
public Form1()
{
InitializeComponent();
hourglass = new HourGlass(this, false);
}
and use it 1 later in a try catch finally block
This works great for me when the LongRunningOperation() is 1 processing messages.
private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e)
{
this.Cursor = Cursors.WaitCursor;
LongRunningOperation();
this.Cursor = Cursors.Arrow;
}
From VB.net VS 2012
Windows.Forms.Cursor.Current = Cursors.Default
0
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.