사용자가 로그인하는 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 헬퍼 클래스로 래핑하여 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;
}
}
용법:
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 환경을 위해서는 다른 스레드에서 Asynchrony를 사용해야합니다.
답변
내 접근 방식은 백그라운드 작업자에서 모든 계산을 수행하는 것입니다.
그런 다음 커서를 다음과 같이 변경하십시오.
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
답변
아래 클래스를 사용하면 도넛에 대한 제안을 “예외 안전”으로 만들 수 있습니다.
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;
}