Cursor.Current VS. This.Cursor

Cursor.Current vs. this.Cursor

Windows sends the window that contains the mouse cursor the WM_SETCURSOR message, giving it an opportunity to change the cursor shape. A control like TextBox takes advantage of that, changing the cursor into a I-bar. The Control.Cursor property determines what shape will be used.

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

The UseWaitCursor property was added in .NET 2.0 to make it easier to display an hourglass. Unfortunately, it doesn't work very well. It requires a WM_SETCURSOR message to change the shape and that won't happen when you set the property to true and then do something that takes a while. 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 whack that into shape, you'll need to use Cursor.Current as well. Here is a little 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 like this:

private void button1_Click(object sender, EventArgs e) {
using (new HourGlass()) {
System.Threading.Thread.Sleep(3000);
}
}

How can I make the cursor turn to the wait cursor?

You can use Cursor.Current.

// Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor;

// Execute your time-intensive hashing code here...

// Set cursor as default arrow
Cursor.Current = Cursors.Default;

However, if the hashing operation is really lengthy (MSDN defines this as more than 2-7 seconds), you should probably use a visual feedback indicator other than the cursor to notify the user of the progress. For a more in-depth set of guidelines, see this article.

Edit:

As @Am pointed out, you may need to call Application.DoEvents(); after Cursor.Current = Cursors.WaitCursor; to ensure that the hourglass is actually displayed.

Can't change the current cursor

This following code is wrong(logically).

finally 
{
Cursor.Current = Cursors.Default;
}

Here what happens is

  1. Cursor will be changed to wait cursor.
  2. Thread will be started and, immediately the Cursor will be changed again to default.(before thread is finished).

So you should place follwing statement after your thread is finished.

        Cursor.Current = Cursors.Default;

Here what you should know is, the call thread.Start(); will immediately return.(does not wait for thread to finish)

Solution1
Remove statement from finally block and do as follows.

void TestConnection()
{
..............
..................


this.Invoke(new MethodInvoker(() =>
{
Cursor = Cursors.Default;
}));
}

Cursor icon doesn't change inside constructor in Windows Forms

Note that Cursor is a property of the form. The selected cursor displays when the mouse is moving over this form. But since the form is not yet visible when the constructor runs, the wait cursor cannot display.

Consider moving long running stuff to a Shown event handler:

private void Form1_Shown(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
try {
Thread.Sleep(2000); // Do long running stuff here
} finally {
Cursor.Current = Cursors.Default;
}
}

Instead, you could also set the wait cursor in the form which is opening this new form.

Cursor.Current = Cursors.WaitCursor;
try {
var frm = new BankApp(); // Constructor is running here.
frm.Show();
} finally {
Cursor.Current = Cursors.Default;
}

If your form is not the main form, you can use the following code to set the wait cursor for all open forms. This should also work in the constructor:

Application.UseWaitCursor = true;
try {
Thread.Sleep(2000); // Do long running stuff here
} finally {
Application.UseWaitCursor = false;
}

The try-finally ensures that the default cursor is also reset, if something should go wrong.

How to set WaitCursor cursor over disabled WinForms

You should handle things differently... there shouldn't be a reason to disable the form to prevent user interaction. Use a dialog box with a progress bar or a message that lets the user know what is going on. Don't give user an impression that the program is hanging or crashing. That is a horrible route to take. Think of a user perspective and what frustrated you when you use others' programs.

However, this worked for me:

this.Enabled = false;
this.UseWaitCursor = true;

Obviously, it only displays when cursor is over the form.

Here's the entire test code:

namespace WindowsFormsApplication1
{
partial class Form1
{
private System.ComponentModel.IContainer components = null;

protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();

this.button1.Location = new System.Drawing.Point(163, 110);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.Enabled = false;
this.UseWaitCursor = true;
}

private System.Windows.Forms.Button button1;
}
}


Related Topics



Leave a reply



Submit