Câu trả lời:
Bạn có thể sử dụng 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;
Tuy nhiên, nếu thao tác băm thực sự dài (MSDN định nghĩa điều này là hơn 2-7 giây), có lẽ bạn nên sử dụng chỉ báo phản hồi trực quan khác với con trỏ để thông báo cho người dùng về tiến trình. Để có một bộ hướng dẫn sâu hơn, xem bài viết này .
Chỉnh sửa:
Như @Am đã chỉ ra, bạn có thể cần gọi Application.DoEvents();
sau Cursor.Current = Cursors.WaitCursor;
để đảm bảo rằng đồng hồ cát thực sự được hiển thị.
Application.UseWaitCursor = true
vàApplication.UseWaitCursor = false
Thực ra,
Cursor.Current = Cursors.WaitCursor;
tạm thời đặt con trỏ Chờ, nhưng không đảm bảo rằng con trỏ Chờ hiển thị cho đến khi kết thúc thao tác của bạn. Các chương trình hoặc điều khiển khác trong chương trình của bạn có thể dễ dàng đặt lại con trỏ trở lại mũi tên mặc định như trên thực tế xảy ra khi bạn di chuyển chuột trong khi hoạt động vẫn đang chạy.
Một cách tốt hơn để hiển thị con trỏ Chờ là đặt thuộc tính UseWaitC tiền ở dạng thành đúng:
form.UseWaitCursor = true;
Điều này sẽ hiển thị con trỏ chờ cho tất cả các điều khiển trên biểu mẫu cho đến khi bạn đặt thuộc tính này thành false. Nếu bạn muốn con trỏ chờ được hiển thị ở cấp Ứng dụng, bạn nên sử dụng:
Application.UseWaitCursor = true;
Dựa trên cách tiếp cận trước đây, cách tiếp cận ưa thích của tôi (vì đây là hành động được thực hiện thường xuyên) là bọc mã con trỏ chờ trong lớp trình trợ giúp IDis Dùng để nó có thể được sử dụng bằng cách sử dụng () (một dòng mã), lấy tham số tùy chọn, chạy mã bên trong, sau đó dọn sạch (khôi phục con trỏ) sau đó.
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;
}
}
Sử dụng:
using (new CursorWait())
{
// Perform some code that shows cursor
}
Sử dụng UseWaitC tiền ở cấp Biểu mẫu hoặc Cửa sổ sẽ dễ dàng hơn . Một trường hợp sử dụng điển hình có thể trông như dưới đây:
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;
}
}
Để có trải nghiệm UI tốt hơn, bạn nên sử dụng Không đồng bộ từ một luồng khác.
Cách tiếp cận của tôi sẽ là thực hiện tất cả các tính toán trong một nhân viên nền.
Sau đó thay đổi con trỏ như thế này:
this.Cursor = Cursors.Wait;
Và trong sự kiện kết thúc của chủ đề, khôi phục con trỏ:
this.Cursor = Cursors.Default;
Lưu ý, điều này cũng có thể được thực hiện cho các điều khiển cụ thể, vì vậy con trỏ sẽ chỉ là đồng hồ cát khi chuột ở trên chúng.
OK vì vậy tôi đã tạo ra một phương thức async tĩnh. Điều đó đã vô hiệu hóa điều khiển khởi chạy hành động và thay đổi con trỏ ứng dụng. Nó chạy hành động như một nhiệm vụ và chờ đợi để kết thúc. Kiểm soát trả về cho người gọi trong khi nó chờ. Vì vậy, ứng dụng vẫn phản hồi, ngay cả khi biểu tượng bận rộn quay.
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;
}
Đây là mẫu mã mẫu chính
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
{
}
}
Tôi đã phải sử dụng một trình ghi nhật ký riêng cho hành động giả (tôi đang sử dụng Nlog) và trình ghi nhật ký chính của tôi đang ghi vào UI (một hộp văn bản có định dạng). Tôi không thể hiển thị con trỏ bận khi chỉ trên một vùng chứa cụ thể trên biểu mẫu (nhưng tôi đã không cố gắng hết sức.) Tất cả các điều khiển đều có thuộc tính UseWaitCoder, nhưng dường như nó không có bất kỳ ảnh hưởng nào đến các điều khiển Tôi đã thử (có thể vì họ không ở trên đầu?)
Đây là nhật ký chính, cho thấy những điều xảy ra theo thứ tự chúng tôi mong đợi:
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
Với lớp học bên dưới, bạn có thể đưa ra gợi ý về Donut "ngoại lệ an toàn".
using (new CursorHandler())
{
// Execute your time-intensive hashing code here...
}
lớp CoderHandler
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;
}
Đối với các ứng dụng Windows Forms, việc vô hiệu hóa tùy chọn UI-Control có thể rất hữu ích. Vì vậy, đề nghị của tôi trông như thế này:
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;
}
}
Sử dụng:
private void UiControl_Click(object sender, EventArgs e)
{
using (new AppWaitCursor(sender))
{
LongRunningCall();
}
}
Sử dụng cái này với WPF:
Cursor = Cursors.Wait;
// Your Heavy work here
Cursor = Cursors.Arrow;