C# 如何使光标转向等待光标?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1568557/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 18:57:17  来源:igfitidea点击:

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

c#.netwinformscursor

提问by Malfist

I have a C# application that has users login to it, and because the hashing algorithm is expensive, it takes a little while to do. How can I display the Wait/Busy Cursor (usually the hourglass) to the user to let them know the program is doing something?

我有一个让用户登录的 C# 应用程序,由于散列算法很昂贵,所以需要一点时间来完成。如何向用户显示等待/忙碌光标(通常是沙漏)以让他们知道程序正在执行某些操作?

The project is in C#.

该项目是在 C# 中。

采纳答案by Donut

You can use Cursor.Current.

您可以使用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 reallylengthy (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.

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

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.

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

回答by Amirshk

My approach would be to make all the calculations in a background worker.

我的方法是在后台工作人员中进行所有计算。

Then change the cursor like this:

然后像这样更改光标:

this.Cursor = Cursors.Wait;

And in the thread's finish event restore the cursor:

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

this.Cursor = Cursors.Default;

Note, this can also be done for specific controls, so the cursor will be the hourglass only when the mouse is above them.

请注意,这也可以用于特定控件,因此只有当鼠标位于它们上方时,光标才会成为沙漏。

回答by draganstankovic

Actually,

实际上,

Cursor.Current = Cursors.WaitCursor;

temporarilysets the Wait cursor, but doesn't ensure that the Wait cursor shows until the end of your operation. Other programs or controls within your program can easily reset the cursor back to the default arrow as in fact happens when you move mouse while operation is still running.

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

A much better way to show the Wait cursor is to set the UseWaitCursor property in a form to true:

显示等待光标的更好方法是将表单中的 UseWaitCursor 属性设置为 true:

form.UseWaitCursor = true;

This will display wait cursor for all controls on the form until you set this property to false. If you want wait cursor to be shown on Application level you should use:

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

Application.UseWaitCursor = true;

回答by dmihailescu

It is easier to use UseWaitCursorat the Form or Window level. A typical use case can look like below:

在窗体或窗口级别使用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;
        }
    }

For a better UI experience you should use Asynchrony from a different thread.

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

回答by mhapps

Building on the previous, my preferred approach (since this is a frequently performed action) is to wrap the wait cursor code in an IDisposable helper class so it can be used with using() (one line of code), take optional parameters, run the code within, then clean up (restore cursor) afterwards.

在前面的基础上,我的首选方法(因为这是一个经常执行的操作)是将等待光标代码包装在 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;
    }
}

Usage:

用法:

using (new CursorWait())
{
    // Perform some code that shows cursor
}

回答by Darrel Lee

OK so I created a static async method. That disabled the control that launches the action and changes the application cursor. It runs the action as a task and waits for to finish. Control returns to the caller while it waits. So the application remains responsive, even while the busy icon spins.

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

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

Here's the code form the main form

这是主窗体的代码

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

I had to use a separate logger for the dummy action (I am using Nlog) and my main logger is writing to the UI (a rich text box). I wasn't able to get the busy cursor show only when over a particular container on the form (but I didn't try very hard.) All controls have a UseWaitCursor property, but it doesn't seem have any effect on the controls I tried (maybe because they weren't on top?)

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

Here's the main log, which shows things happening in the order we expect:

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

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

回答by Georg

With the class below you can make the suggestion of Donut "exception safe".

通过下面的课程,您可以提出甜甜圈“异常安全”的建议。

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

the class CursorHandler

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

回答by wenha

Okey,Other people's view are very clear, but I would like to do some added, as follow:

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

Cursor tempCursor = Cursor.Current;

Cursor.Current = Cursors.WaitCursor;

//do Time-consuming Operations         

Cursor.Current = tempCursor;

回答by Alzayed

Use this with WPF:

将此与 WPF 一起使用:

Cursor = Cursors.Wait;

// Your Heavy work here

Cursor = Cursors.Arrow;

回答by HEF

For Windows Forms applications an optional disabling of a UI-Control can be very useful. So my suggestion looks like this:

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

Usage:

用法:

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