it-swarm.com.de

Wie kann ich den Cursor zum Wait-Cursor drehen lassen?

Ich habe eine C # -Anwendung, bei der sich Benutzer anmelden, und da der Hash-Algorithmus teuer ist, dauert es einige Zeit. Wie kann ich dem Benutzer den Wait/Busy Cursor (normalerweise die Sanduhr) anzeigen lassen, um ihn wissen zu lassen, dass das Programm etwas tut?

Das Projekt ist in C #.

214
Malfist

Sie können Cursor.Current verwenden.

// Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor;

// Execute your time-intensive hashing code here...

// Set cursor as default arrow
Cursor.Current = Cursors.Default;

Wenn der Hash-Vorgang jedoch wirklich lang ist (MSDN definiert dies mehr als 2 bis 7 Sekunden), sollten Sie wahrscheinlich einen visuellen Feedback-Indikator außer dem Cursor verwenden, um den Benutzer über den Fortschritt zu informieren. Weitere ausführliche Richtlinien finden Sie in diesem Artikel .

Bearbeiten:
Wie @Am darauf hingewiesen hat, müssen Sie möglicherweise Application.DoEvents(); nach Cursor.Current = Cursors.WaitCursor; aufrufen, um sicherzustellen, dass die Sanduhr tatsächlich angezeigt wird. 

382
Donut

Tatsächlich, 

Cursor.Current = Cursors.WaitCursor;

vorübergehend setzt den Wait-Cursor, stellt jedoch nicht sicher, dass der Wait-Cursor bis zum Ende des Vorgangs angezeigt wird. Andere Programme oder Steuerelemente in Ihrem Programm können den Cursor auf den Standardpfeil zurücksetzen. Dies ist der Fall, wenn Sie die Maus bewegen, während der Vorgang noch ausgeführt wird. 

Eine viel bessere Möglichkeit, den Wait-Cursor anzuzeigen, besteht darin, die UseWaitCursor-Eigenschaft in einem Formular auf true zu setzen:

form.UseWaitCursor = true;

Daraufhin wird der Wait-Cursor für alle Steuerelemente im Formular angezeigt, bis Sie diese Eigenschaft auf false festlegen. Wenn der Wait-Cursor auf Anwendungsebene angezeigt werden soll, sollten Sie Folgendes verwenden:

Application.UseWaitCursor = true;
149
draganstankovic

Aufbauend auf dem vorherigen Ansatz besteht mein bevorzugter Ansatz (da dies eine häufig durchgeführte Aktion ist) darin, den Wait-Cursor-Code in eine IDisposable-Helper-Klasse einzuhüllen, sodass er mit using () (eine Codezeile) verwendet werden kann, optionale Parameter ausführen und ausführen den Code in, dann bereinigen (Cursor wiederherstellen).

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

Verwendungszweck:

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

Es ist einfacher, UseWaitCursor auf Formular- oder Fensterebene zu verwenden. Ein typischer Anwendungsfall kann wie folgt aussehen:

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

Für eine bessere Benutzeroberfläche sollten Sie Asynchrony aus einem anderen Thread verwenden.

22
dmihailescu

Mein Ansatz wäre, alle Berechnungen in einem Hintergrundarbeiter durchzuführen.

Dann ändern Sie den Cursor wie folgt:

this.Cursor = Cursors.Wait;

Und im Finish-Ereignis des Threads stellen Sie den Cursor wieder her:

this.Cursor = Cursors.Default;

Beachten Sie, dass dies auch für bestimmte Steuerelemente möglich ist, sodass der Cursor nur dann als Sanduhr angezeigt wird, wenn sich die Maus darüber befindet.

17
Amirshk

OK, also habe ich eine statische Async-Methode erstellt. Dadurch wurde das Steuerelement deaktiviert, mit dem die Aktion gestartet und der Anwendungscursor geändert wird. Es führt die Aktion als Task aus und wartet auf den Abschluss. Während des Wartens kehrt die Steuerung zum Anrufer zurück. So bleibt die Anwendung auch dann aktiv, wenn das Symbol "Beschäftigt" rotiert.

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

Hier ist das Code-Formular das Hauptformular

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

Ich musste einen separaten Logger für die Dummy-Aktion verwenden (ich verwende Nlog), und mein Hauptlogger schreibt an die Benutzeroberfläche (ein Rich-Text-Feld). Ich konnte die Auslastung des Cursors nur über einen bestimmten Container im Formular abrufen (aber ich habe mich nicht sehr bemüht.) Alle Steuerelemente verfügen über eine UseWaitCursor-Eigenschaft, es scheint jedoch keine Auswirkungen auf die Steuerelemente zu haben Ich habe es versucht (vielleicht, weil sie nicht oben waren?)

Hier ist das Hauptprotokoll, das die Ereignisse in der von uns erwarteten Reihenfolge zeigt:

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
4
Darrel Lee

Okey, die Sichtweise anderer Leute ist sehr klar, aber ich möchte Folgendes hinzufügen:

Cursor tempCursor = Cursor.Current;

Cursor.Current = Cursors.WaitCursor;

//do Time-consuming Operations         

Cursor.Current = tempCursor;
2
wenha

Für Windows Forms-Anwendungen kann eine optionale Deaktivierung eines UI-Controls sehr hilfreich sein. Mein Vorschlag sieht also so aus:

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

Verwendungszweck:

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

Mit der folgenden Klasse können Sie den Vorschlag von Donut "ausnahmesicher" machen.

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

die Klasse 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;
}
1
Georg

Verwenden Sie dies mit WPF:

Cursor = Cursors.Wait;

// Your Heavy work here

Cursor = Cursors.Arrow;
0
Alzayed