如何让光标转到等待光标?

Mal*_*ist 243 .net c# cursor winforms

我有一个C#应用程序,用户登录它,并且因为散列算法很昂贵,所以需要一些时间.如何向用户显示等待/忙碌光标(通常是沙漏),让他们知道程序正在做什么?

该项目在C#中.

Don*_*nut 424

你可以用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;
Run Code Online (Sandbox Code Playgroud)

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

编辑:
作为@Am指出的那样,你可能需要调用Application.DoEvents();之后Cursor.Current = Cursors.WaitCursor;,以确保沙漏实际显示.

  • 如果在时间密集型代码期间不会调用消息循环,则无需更改游标.要启用它,您需要在第一个游标集之后添加_Application.DoEvents(); _. (23认同)
  • 在设置Current之后你可能想要一个try..finally阻塞(确保Current重置为Default). (15认同)
  • 最好使用`Application.UseWaitCursor = true`和`Application.UseWaitCursor = false` (14认同)
  • 仅供参考,我无法完成上述工作,但通过将其更改为this.cursor = cursors.waitcursor; 有效. (7认同)
  • 如果我在Cursor.Current = Cursors.WaitCursor之后使用Application.DoEvents(),则不显示沙漏但是,它确实在没有Application.DoEvents()的情况下工作.不确定为什么 (4认同)
  • @GianpieroCaretti 为什么会这样?请解释。 (2认同)

dra*_*vic 163

其实,

Cursor.Current = Cursors.WaitCursor;
Run Code Online (Sandbox Code Playgroud)

临时设置等待光标,但不保证等待光标显示直到操作结束.程序中的其他程序或控件可以轻松地将光标重置回默认箭头,因为在操作仍在运行时移动鼠标时会发生这种情况.

显示Wait游标的一种更好的方法是将表单中的UseWaitCursor属性设置为true:

form.UseWaitCursor = true;
Run Code Online (Sandbox Code Playgroud)

这将显示表单上所有控件的等待光标,直到您将此属性设置为false.如果要在应用程序级别显示等待光标,则应使用:

Application.UseWaitCursor = true;
Run Code Online (Sandbox Code Playgroud)

  • 这比公认的解决方案好得多! (11认同)
  • 在Application下找不到UseWaitCursor! (2认同)
  • 我发现,在操作结束时设置 form.UseWaitCursor = false 时,它​​实际上不会重置光标,直到您移动或单击鼠标。OTOH,form.Cursor 没有这个问题。我根本无法让 Cursor.Current 工作。 (2认同)

mha*_*pps 33

在前面的基础上,我的首选方法(因为这是一个经常执行的操作)是将等待光标代码包装在IDisposable辅助类中,以便它可以与using()(一行代码)一起使用,获取可选参数,运行其中的代码,然后清理(恢复光标).

public class CursorWait : IDisposable
{
    public CursorWait(bool appStarting = false, bool applicationCursor = false)
    {
        // Wait
        Cursor.Current = appStarting ? Cursors.AppStarting : Cursors.WaitCursor;
        if (applicationCursor) Application.UseWaitCursor = true;
    }

    public void Dispose()
    {
        // Reset
        Cursor.Current = Cursors.Default;
        Application.UseWaitCursor = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

using (new CursorWait())
{
    // Perform some code that shows cursor
}
Run Code Online (Sandbox Code Playgroud)


dmi*_*scu 26

在窗体或窗口级别使用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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

为了获得更好的UI体验,您应该使用来自不同线程的Asynchrony.

  • 这应该是接受的答案。它是唯一一个使用 try-finally 的。 (2认同)

Ami*_*shk 19

我的方法是在后台工作程序中进行所有计算.

然后像这样更改光标:

this.Cursor = Cursors.Wait;
Run Code Online (Sandbox Code Playgroud)

并在线程的完成事件中恢复光标:

this.Cursor = Cursors.Default;
Run Code Online (Sandbox Code Playgroud)

请注意,这也可以针对特定控件执行,因此仅当鼠标位于其上方时,光标才是沙漏.


小智 10

对于 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

private void UiControl_Click(object sender, EventArgs e)
{
    using (new AppWaitCursor(sender))
    {
        LongRunningCall();
    }
}
Run Code Online (Sandbox Code Playgroud)


Dar*_*Lee 6

好的,我创建了一个静态异步方法。这禁用了启动操作并更改应用程序光标的控件。它将操作作为任务运行并等待完成。当调用者等待时,控制权返回给调用者。因此,即使忙碌图标旋转,应用程序也能保持响应。

async public static void LengthyOperation(Control control, Action action)
{
    try
    {
        control.Enabled = false;
        Application.UseWaitCursor = true;
        Task doWork = new Task(() => action(), TaskCreationOptions.LongRunning);
        Log.Info("Task Start");
        doWork.Start();
        Log.Info("Before Await");
        await doWork;
        Log.Info("After await");
    }
    finally
    {
        Log.Info("Finally");
        Application.UseWaitCursor = false;
        control.Enabled = true;
    }
Run Code Online (Sandbox Code Playgroud)

这是主窗体的代码

    private void btnSleep_Click(object sender, EventArgs e)
    {
        var control = sender as Control;
        if (control != null)
        {
            Log.Info("Launching lengthy operation...");
            CursorWait.LengthyOperation(control, () => DummyAction());
            Log.Info("...Lengthy operation launched.");
        }

    }

    private void DummyAction()
    {
        try
        {
            var _log = NLog.LogManager.GetLogger("TmpLogger");
            _log.Info("Action - Sleep");
            TimeSpan sleep = new TimeSpan(0, 0, 16);
            Thread.Sleep(sleep);
            _log.Info("Action - Wakeup");
        }
        finally
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)

我必须使用单独的记录器来执行虚拟操作(我正在使用 Nlog),而我的主记录器正在写入 UI(富文本框)。仅当在表单上的特定容器上时,我无法显示繁忙的光标(但我没有努力尝试。)所有控件都有 UseWaitCursor 属性,但它似乎对控件没有任何影响我尝试过(也许是因为他们不在上面?)

这是主日志,它显示了按照我们期望的顺序发生的事情:

16:51:33.1064 Launching lengthy operation...
16:51:33.1215 Task Start
16:51:33.1215 Before Await
16:51:33.1215 ...Lengthy operation launched.
16:51:49.1276 After await
16:51:49.1537 Finally
Run Code Online (Sandbox Code Playgroud)


小智 5

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

Cursor tempCursor = Cursor.Current;

Cursor.Current = Cursors.WaitCursor;

//do Time-consuming Operations         

Cursor.Current = tempCursor;
Run Code Online (Sandbox Code Playgroud)