我有一个具有用户登录到其C#应用程序,并且由于散列算法是昂贵的,它需要一点时间做。 我怎样才能显示等待/忙光标(通常是沙漏)给用户,让他们知道程序是做什么?
该项目是在C#中。
我有一个具有用户登录到其C#应用程序,并且由于散列算法是昂贵的,它需要一点时间做。 我怎样才能显示等待/忙光标(通常是沙漏)给用户,让他们知道程序是做什么?
该项目是在C#中。
您可以使用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();
后Cursor.Current = Cursors.WaitCursor;
以确保沙漏实际显示。
其实,
Cursor.Current = Cursors.WaitCursor;
临时设置等待光标,但不保证等待光标显示,直到你的操作结束。 你的程序中的其它程序或控件可以轻松重置光标回到默认箭头在当你移动鼠标操作时仍在运行的事实发生。
一个更好的方式来显示等待光标是设置UseWaitCursor属性的形式为true:
form.UseWaitCursor = true;
这将显示等待光标用于所有控件的形式,直到你将此属性设置为false。 如果你想等待光标显示你应该使用应用程序级别:
Application.UseWaitCursor = true;
在以前,我的首选方法(因为这是一个经常执行的动作)大厦包裹等待光标的代码在IDisposable的辅助类,因此它可以使用()(一行代码)可以使用,采取可选参数,运行在代码中,然后清理(恢复光标)之后。
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;
}
}
用法:
using (new CursorWait())
{
// Perform some code that shows cursor
}
这是比较容易在窗体或窗口级别使用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体验,你应该从不同的线程中使用异步性。
我的方法是使在后台工作的所有计算。
然后改变光标这样的:
this.Cursor = Cursors.Wait;
而在线程结束时恢复光标:
this.Cursor = Cursors.Default;
请注意,这也可以为特定的控制完成,因此光标将沙漏只有当鼠标在他们之上。
行,所以我创建了一个静态的异步方法。 这禁用了启动行动,并改变应用程序的光标控制。 它运行的行动任务,并等待到结束。 在等待控制返回给调用者。 因此,应用程序仍然可以做出响应,即使在繁忙的图标旋转。
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;
}
下面的代码形式的主要形式
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
{
}
}
我不得不使用诱敌动作(我用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
奥基,其他人的看法是很清楚,但我想做些补充如下:
Cursor tempCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
//do Time-consuming Operations
Cursor.Current = tempCursor;
下面你的类可以让甜甜圈的“异常安全”的建议。
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;
}
与WPF使用此:
Cursor = Cursors.Wait;
// Your Heavy work here
Cursor = Cursors.Arrow;