Hoe kan ik de cursor naar de wachtcursor laten draaien?

Hoe kan ik de Wacht/Bezet-cursor (meestal de zandloper) aan de gebruiker laten zien om te laten weten dat het programma iets doet?


Antwoord 1, autoriteit 100%

U kunt de 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;

Als de hash-bewerking echter echtlang duurt (MSDN definieert dit als meer dan 2-7 seconden), moet u waarschijnlijk een andere visuele feedback-indicator dan de cursor gebruiken om de gebruiker op de hoogte te stellen van de voortgang. Zie dit artikel voor een uitgebreidere set richtlijnen. .

Bewerken:
Zoals @Am al aangaf, moet u mogelijk Application.DoEvents();aanroepen na Cursor.Current = Cursors.WaitCursor;om er zeker van te zijn dat de zandloper daadwerkelijk wordt weergegeven.


Antwoord 2, autoriteit 37%

Eigenlijk,

Cursor.Current = Cursors.WaitCursor;

tijdelijkstelt de Wacht-cursor in, maar zorgt er niet voor dat de Wacht-cursor wordt weergegeven tot het einde van uw bewerking. Andere programma’s of bedieningselementen in uw programma kunnen de cursor gemakkelijk terugzetten naar de standaardpijl, zoals in feite gebeurt wanneer u de muis beweegt terwijl de bewerking nog loopt.

Een veel betere manier om de Wait-cursor weer te geven, is door de eigenschap UseWaitCursor in een vorm in te stellen op true:

form.UseWaitCursor = true;

Hiermee wordt de wachtcursor weergegeven voor alle besturingselementen op het formulier totdat u deze eigenschap instelt op false.
Als u wilt dat de wachtcursor wordt weergegeven op applicatieniveau, moet u het volgende gebruiken:

Application.UseWaitCursor = true;

Antwoord 3, autoriteit 8%

Voortbouwend op de vorige, mijn voorkeursbenadering (aangezien dit een vaak uitgevoerde actie is) is om de wachtcursorcode in een IDisposable-helperklasse in te pakken, zodat deze kan worden gebruikt met behulp van () (één regel code), neem optioneel parameters, voer de code erin uit en ruim daarna op (cursor herstellen).

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

Gebruik:

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

Antwoord 4, autoriteit 7%

Het is gemakkelijker om UseWaitCursorte gebruiken op formulier- of vensterniveau.
Een typische use-case kan er als volgt uitzien:

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

Voor een betere UI-ervaring moet je Asynchrony van een andere thread gebruiken.


Antwoord 5, autoriteit 5%

Mijn aanpak zou zijn om alle berekeningen in een achtergrondmedewerker te maken.

Verander dan de cursor als volgt:

this.Cursor = Cursors.Wait;

En herstel de cursor in de finish-gebeurtenis van de thread:

this.Cursor = Cursors.Default;

Let op, dit kan ook worden gedaan voor specifieke bedieningselementen, dus de cursor is alleen de zandloper als de muis erboven staat.


Antwoord 6

OK, dus ik heb een statische asynchrone methode gemaakt. Dat heeft de besturing uitgeschakeld die de actie start en de applicatiecursor verandert. Het voert de actie uit als een taak en wacht tot het is voltooid. Controle keert terug naar de beller terwijl deze wacht. De applicatie blijft dus responsief, zelfs als het bezet-pictogram draait.

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 is de code van het hoofdformulier

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

Ik moest een aparte logger gebruiken voor de dummy-actie (ik gebruik Nlog) en mijn hoofdlogger schrijft naar de gebruikersinterface (een rich-text-vak). Ik kon de drukke cursor niet alleen laten zien wanneer ik boven een bepaalde container op het formulier stond (maar ik heb niet erg mijn best gedaan.) Alle besturingselementen hebben een UseWaitCursor-eigenschap, maar het lijkt geen effect te hebben op de besturingselementen Ik heb het geprobeerd (misschien omdat ze niet bovenaan stonden?)

Hier is het hoofdlogboek, waarin de dingen worden weergegeven in de volgorde die we verwachten:

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

Antwoord 7

Oké, de mening van anderen is heel duidelijk, maar ik zou er graag wat aan toevoegen, zoals:

Cursor tempCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
//do Time-consuming Operations         
Cursor.Current = tempCursor;

Antwoord 8

Gebruik dit met WPF:

Cursor = Cursors.Wait;
// Your Heavy work here
Cursor = Cursors.Arrow;

Antwoord 9

Voor Windows Forms-toepassingen kan het optioneel uitschakelen van een UI-Control erg handig zijn. Dus mijn suggestie ziet er als volgt uit:

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

Gebruik:

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

Antwoord 10

Met de onderstaande les kun je de suggestie van Donut “uitzonderlijk veilig” maken.

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

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

Other episodes