开发者

Displaying wait cursor in while backgroundworker is running

开发者 https://www.devze.com 2023-02-13 06:56 出处:网络
During the start of my windows application, I have to make a call to a web service to retrieve some default data to load onto my application. During the load of the form, I run a backgroundworker to r

During the start of my windows application, I have to make a call to a web service to retrieve some default data to load onto my application. During the load of the form, I run a backgroundworker to retrieve this data. I want to display the wait cursor until this data is retrieved. How would I do this?

I've tried setting the wait cursor before calling the backgroundworker to run. When I report a progress of 100 then I set it back to the default cursor. The wait cursor comes up but when I move the mouse it disappears.

Environment:

  • Windows 7 Pro 64-bit
  • VS2010 C# .NET 4.0
  • Windows Forms

EDIT: I am setting the cursor the way Jay Riggs suggested. It only works if I don't move the mouse.

**UPDATE: I have created a button click which does the following: When I do the button click and move my mouse, the wait cursor appears regardless if I move my mouse or not.

void BtnClick()
{
  Cursor = Cursors.WaitCursor;
  Thread.Sleep(8000);
  Cursor = Cursors.Default;
}

If I do the following: I see the wait cursor and when I move the mouse it disappears inside the form. If I move to my status bar or the menu bar the wait cursor appears.

Cursor = Cursors.WaitCursor;
if (!backgroundWorker.IsBusy)
{
  backGroundWorker.RunWorkerAsync();
}

void backGroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
  Thread.Sleep(8000);
}

void backGroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  Cursor = Cursors.Default;
}

If I do the following: The wait cursor appears开发者_如何学Python and when I move the mouse it still appears but will sometimes flicker off and on when moving in text fields. Although the cursor changes to the wait cursor, it doesn't prevent you from clicking on anything.

if (!backgroundWorker.IsBusy)
{
  backGroundWorker.RunWorkerAsync();
}

void backGroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
  UseWaitCursor = true;
  Thread.Sleep(8000);
}

void backGroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  UseWaitCursor = false;
}


Does UseWaitCursor work? (Set to true when calling RunWorkerAsync(), and false when the completion event is called). What are you using to set the cursor now?


Don't display a wait cursor for this - instead, use a control on your form to indicate that the backgroundworker is busy doing something. The wait cursor is an appropriate indicator for the UI thread to use (since it indicates that the user can't/shouldn't touch anything), but it's not appropriate for something happening in the background.


In WPF, I've done this by setting the Mouse.OverrideCursor property to Cursors.Wait before I start the Backgroundworker, and then resetting it to null in the RunWorkerCompleted event. Seems to work pretty well so far.

public void go()
{
    BackgroundWorker thread = new BackgroundWorker();

    thread.DoWork += run;
    thread.RunWorkerCompleted += taskCompleted;
    thread.WorkerReportsProgress = true;

    // Change mouse cursor to busy
    Mouse.OverrideCursor = Cursors.Wait;

    thread.RunWorkerAsync();
}

private void taskCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Reset mouse cursor
    Mouse.OverrideCursor = null;
}


You should use the BGW's RunWorkerCompleted event to set your cursor back to the default.

EDIT:

Set your cursor to wait by calling this code before starting up your BGW:

this.Cursor = Cursors.WaitCursor;

Reset your cursor in the BGW's RunWorkerCompleted event by:

this.Cursor = Cursors.Default;


There are a lot of answers here already but I found another solution that worked for me so I'd figured I list it.

private void ShowWaitCursor(){
    Application.UseWaitCursor = true; //keeps waitcursor even when the thread ends.
    System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; //Normal mode of setting waitcursor
}

private void ShowNormalCursor(){
    Application.UseWaitCursor = false;
    System.Windows.Forms.Cursor.Current = Cursors.Default;
}

I use both in line like this and it seams to work the way I expect all the time. Especially when I want to have a wait cursor showing while a worker is running. Hope this helps anyone else still looking.


In the MS forums thread UseWaitCursor not working but Cursor = Cursors.WaitCursor does../ & Cursor.Current vs. this.Cursor

it was confirmed that WF's implementation of UseWaitCursor missed an opportunity to make it actually work to show an hourglass cursor and shown the HourGlass class, that can be used with "using" block

using (new HourGlass()) {
        // Do something that takes time...
        System.Threading.Thread.Sleep(2000);
      }


Something else must be setting the cursor. The code below sets a wait cursor when the timer starts, and then sets the cursor back to the previous value after the timer expires. It works as expected: the wait cursor remains throughout the interval. Of course, moving the cursor outside the form will show the cursor for whatever window the mouse cursor is over, but moving it back to my form shows the wait cursor.

public partial class MyDialog : Form
{
    private Timer myTimer;
    public MyDialog()
    {
        InitializeComponent();
        myTimer = new Timer();
        myTimer.Tick += new EventHandler(myTimer_Tick);
        myTimer.Interval = 5000;
        myTimer.Enabled = false;
    }

    private Cursor SaveCursor;
    private void button1_Click(object sender, EventArgs e)
    {
        Cursor = Cursors.WaitCursor;
        myTimer.Enabled = true;
    }

    void myTimer_Tick(object sender, EventArgs e)
    {
        Cursor = SaveCursor;
        myTimer.Enabled = false;
    }
}


The Microsoft Reference Source gives us the implementation of Control.UseWaitCursor and Control.Cursor. If you examine Control.Cursor, you'll see that if UseWaitCursor is set to True, Control.Cursor returns Cursor.WaitCursor regardless of what cursor is set on the control. Because of this behavior, the value returned from Control.Cursor can't be cached.

// DON'T DO THIS: THIS CODE WILL BREAK IF UseWaitCursor IS SET TO TRUE
// Store the original cursor
Cursor cachedCursor = this.Cursor;

// Set the cursor to a wait cursor.
this.Cursor = Cursors.WaitCursor;

// Perform some task

// Restore the original cursor
this.Cursor = cachedCursor;

While the above looks harmless enough, it can instantly lead to problems if someone sets Control.UseWaitCursor to True before it is executed. The result of which would be a stuck wait cursor due to Control.Cursor returning Cursors.WaitCursor on the first line in the above. A better method for changing the cursor is thus:

// Change the cursor as needed
this.Cursor = Cursors.WaitCursor;

// Perform some task

// Restore the default cursor when finished.
this.Cursor = this.DefaultCursor;

For the vast majority of things, the above should be sufficient to show a wait cursor when needed. However, if a child of a control also modifies the cursor, the cursor set by the child will override that which is set on the parent. IE if you set the cursor of a label to Cursors.IBeam on a form which sets its cursor to Cursors.WaitCursor, the label will display an IBeam while the form displays the WaitCursor. Only controls where Control.Cursor returns the same value as Control.DefaultCursor will display the WaitCursor set on the form in this case. This is where Control.UseWaitCursor comes in. Setting UseWaitCursor on a form sets UseWaitCursor on all of its children as well. As long as none of the controls on the form are using the broken code above. The DataGridView is only one of the many controls that used the broken code above.

But.. what if you don't want a WaitCursor and want to maintain the cursor set externally by a user of your control? In this case, your options are limited, you must override the Cursor property of your control to receive the cursor set by a user of your control OR you must use reflection to gain access to the internal cursor value stored by the base Control class. Then, and only then can you use the first method above for caching and restoring the cursor. *Note: you must cache the internal cursor value set by the user of your control, not the result from base.Cursor!


Here is what I'm doing now, I hope this help.

private void LoadWaitCursor()
{
    this.Dispatcher.Invoke((Action)(() =>
    {
        Mouse.OverrideCursor = Cursors.Wait;
    }));
}
private void LoadDefaultCursor()
{
    this.Dispatcher.Invoke((Action)(() =>
    {
        Mouse.OverrideCursor = null;
    }));
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号