Отображение курсора ожидания во время работы фонового работника - PullRequest
16 голосов
/ 26 февраля 2011

Во время запуска моего приложения Windows я должен позвонить в веб-службу, чтобы получить данные по умолчанию для загрузки в мое приложение. Во время загрузки формы я запускаю фонового работника, чтобы получить эти данные. Я хочу отобразить курсор ожидания, пока эти данные не будут получены. Как бы я это сделал?

Я попытался установить курсор ожидания перед вызовом фонового работника для запуска. Когда я сообщаю о прогрессе 100, я возвращаю его к курсору по умолчанию. Курсор ожидания появляется, но когда я двигаю мышь, он исчезает.

Окружающая среда:

  • Windows 7 Pro, 64-разрядная
  • VS2010 C # .NET 4.0
  • Windows Forms

EDIT: Я устанавливаю курсор так, как предложил Джей Риггс. Это работает, только если я не двигаю мышь.

** UPDATE: Я создал щелчок кнопки, который выполняет следующие действия: когда я нажимаю кнопку и двигаю мышь, курсор ожидания появляется независимо от того, двигаю я мышь или нет.

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

Если я сделаю следующее: я вижу курсор ожидания, и когда я перемещаю мышь, он исчезает внутри формы. Если я перейду к моей строке состояния или строке меню, появится курсор ожидания.

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 (!backgroundWorker.IsBusy)
{
  backGroundWorker.RunWorkerAsync();
}

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

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

Ответы [ 9 ]

18 голосов
/ 26 февраля 2011

Работает ли UseWaitCursor? (Устанавливается в true при вызове RunWorkerAsync () и в false, когда вызывается событие завершения). Что вы используете, чтобы установить курсор сейчас?

11 голосов
/ 26 февраля 2011

Не отображайте курсор ожидания для этого - вместо этого используйте элемент управления в своей форме, чтобы указать, что фоновый работник занят чем-то. Курсор ожидания является подходящим индикатором для потока пользовательского интерфейса (поскольку он указывает, что пользователь не может / не должен ничего трогать), но он не подходит для того, что происходит в фоновом режиме.

6 голосов
/ 26 февраля 2011

В WPF я сделал это, установив для свойства Mouse.OverrideCursor значение Cursors.Wait, прежде чем запускать Backgroundworker, а затем сбросив его на null в событии RunWorkerCompleted. Кажется, до сих пор работает очень хорошо.

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;
}
4 голосов
/ 26 февраля 2011

Вы должны использовать событие RunWorkerCompleted BGW , чтобы вернуть курсор по умолчанию.

EDIT:

Установите курсор на ожидание, позвонив по этому коду перед запуском вашего BGW:

this.Cursor = Cursors.WaitCursor;

Сброс вашего курсора в событии RunWorkerCompleted BGW:

this.Cursor = Cursors.Default;
0 голосов
/ 20 июля 2017

Здесь уже есть много ответов, но я нашел другое решение, которое сработало для меня, поэтому я решил, что перечислю его.

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;
}

Я использую обе строки, как эта, и она работаеткак я ожидаю все время.Особенно, когда я хочу, чтобы курсор ожидания показывался во время работы работника.Надеюсь, это поможет всем, кто еще ищет.

0 голосов
/ 16 июня 2016

Вот что я делаю сейчас, надеюсь, это поможет.

private void LoadWaitCursor()
{
    this.Dispatcher.Invoke((Action)(() =>
    {
        Mouse.OverrideCursor = Cursors.Wait;
    }));
}
private void LoadDefaultCursor()
{
    this.Dispatcher.Invoke((Action)(() =>
    {
        Mouse.OverrideCursor = null;
    }));
}
0 голосов
/ 13 апреля 2015

Справочный источник Microsoft дает нам реализацию Control.UseWaitCursor и Control.Cursor . Если вы изучите Control.Cursor, то увидите, что если для UseWaitCursor установлено значение True, Control.Cursor возвращает Cursor.WaitCursor независимо от того, какой курсор установлен на элементе управления. Из-за этого поведения значение, возвращаемое из Control.Cursor, не может быть кэшировано.

// 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;

Хотя вышеприведенное выглядит достаточно безвредным, оно может мгновенно привести к проблемам, если кто-то установит Control.UseWaitCursor в True до его выполнения. Результатом будет зависание курсора ожидания из-за Control.Cursor, возвращающего Cursors.WaitCursor в первой строке выше. Таким образом, лучший метод для изменения курсора:

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

// Perform some task

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

Для подавляющего большинства вещей вышеприведенного должно быть достаточно, чтобы при необходимости отображать курсор ожидания. Однако, если дочерний элемент управления также изменяет курсор, курсор, установленный дочерним элементом, переопределит тот, который установлен в родительском элементе. То есть, если вы устанавливаете курсор метки в Cursors.IBeam в форме, которая устанавливает курсор в Cursors.WaitCursor, метка будет отображать IBeam, в то время как форма отображает WaitCursor. Только элементы управления, в которых Control.Cursor возвращает то же значение, что и Control.DefaultCursor, будут отображать набор WaitCursor в форме в этом случае. Вот тут-то и появляется Control.UseWaitCursor. Установка UseWaitCursor в форме также устанавливает UseWaitCursor для всех его дочерних элементов. Пока ни один из элементов управления в форме не использует неработающий код выше. DataGridView - это только один из многих элементов управления, которые использовали неработающий код выше.

Но .. что если вы не хотите WaitCursor и хотите сохранить курсор установленным пользователем вашего элемента управления? В этом случае ваши параметры ограничены, вы должны переопределить свойство Cursor вашего элемента управления, чтобы получить курсор, установленный пользователем вашего элемента управления, ИЛИ вы должны использовать отражение, чтобы получить доступ к значению внутреннего курсора, сохраненному базовым классом Control. Тогда и только тогда вы можете использовать первый метод, описанный выше, для кэширования и восстановления курсора. * Примечание: вы должны кэшировать значение внутреннего курсора, установленное пользователем вашего элемента управления, а не результат из base.Cursor!

0 голосов
/ 26 февраля 2011

Что-то еще должно быть установка курсора.Приведенный ниже код устанавливает курсор ожидания при запуске таймера, а затем устанавливает курсор обратно на предыдущее значение после истечения таймера.Он работает как положено: курсор ожидания остается на протяжении всего интервала.Конечно, перемещение курсора за пределы формы покажет курсор для любого окна, над которым находится курсор мыши, но перемещение его обратно в мою форму покажет курсор ожидания.

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;
    }
}
...