我如何向用户显示等待/忙碌游标(通常是沙漏),让他们知道程序正在做什么?


当前回答

实际上,

Cursor.Current = Cursors.WaitCursor;

临时设置等待游标,但不确保等待游标直到操作结束才显示。程序中的其他程序或控件可以很容易地将光标重置回默认箭头,就像在操作仍在运行时移动鼠标一样。

一个更好的显示等待游标的方法是在表单中设置UseWaitCursor属性为true:

form.UseWaitCursor = true;

这将显示窗体上所有控件的等待游标,直到将此属性设置为false。 如果你想等待光标显示在应用程序级别,你应该使用:

Application.UseWaitCursor = true;

其他回答

好的,其他人的观点很清楚,但我想补充一些,如下:

Cursor tempCursor = Cursor.Current;

Cursor.Current = Cursors.WaitCursor;

//do Time-consuming Operations         

Cursor.Current = tempCursor;

在窗体或窗口级别使用UseWaitCursor更容易。 一个典型的用例如下所示:

    private void button1_Click(object sender, EventArgs e)
    {

        try
        {
            this.Enabled = false;//optional, better target a panel or specific controls
            this.UseWaitCursor = true;//from the Form/Window instance
            Application.DoEvents();//messages pumped to update controls
            //execute a lengthy blocking operation here, 
            //bla bla ....
        }
        finally
        {
            this.Enabled = true;//optional
            this.UseWaitCursor = false;
        }
    }

为了获得更好的UI体验,你应该在不同的线程中使用异步。

你可以使用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;

但是,如果散列操作非常长(MSDN将其定义为超过2-7秒),则可能应该使用游标以外的可视反馈指示器来通知用户进度。有关更深入的指导方针,请参阅本文。

编辑: 正如@Am指出的那样,您可能需要调用Application.DoEvents();在游标。Current = Cursors.WaitCursor;以确保沙漏是真实显示的。

使用下面的类,您可以使Donut的建议“异常安全”。

using (new CursorHandler())
{
    // Execute your time-intensive hashing code here...
}

类CursorHandler

public class CursorHandler
    : IDisposable
{
    public CursorHandler(Cursor cursor = null)
    {
        _saved = Cursor.Current;
        Cursor.Current = cursor ?? Cursors.WaitCursor;
    }

    public void Dispose()
    {
        if (_saved != null)
        {
            Cursor.Current = _saved;
            _saved = null;
        }
    }

    private Cursor _saved;
}

对于Windows窗体应用程序,可选的禁用ui控件是非常有用的。所以我的建议是这样的:

public class AppWaitCursor : IDisposable
{
    private readonly Control _eventControl;

    public AppWaitCursor(object eventSender = null)
    {
         _eventControl = eventSender as Control;
        if (_eventControl != null)
            _eventControl.Enabled = false;

        Application.UseWaitCursor = true;
        Application.DoEvents();
    }

    public void Dispose()
    {
        if (_eventControl != null)
            _eventControl.Enabled = true;

        Cursor.Current = Cursors.Default;
        Application.UseWaitCursor = false;
    }
}

用法:

private void UiControl_Click(object sender, EventArgs e)
{
    using (new AppWaitCursor(sender))
    {
        LongRunningCall();
    }
}