Come posso aggiornare la riga corrente in un'app console Windows C #?


507

Quando si crea un'app console di Windows in C #, è possibile scrivere sulla console senza estendere una riga corrente o passare a una nuova riga? Ad esempio, se voglio mostrare una percentuale che rappresenta quanto è vicino un processo al completamento, vorrei solo aggiornare il valore sulla stessa riga del cursore e non devo mettere ogni percentuale su una nuova riga.

Questo può essere fatto con un'app console "standard" C #?


Se sei DAVVERO interessato a fantastiche interfacce da riga di comando, dai un'occhiata a curses / ncurses.
Charles Addis il

@CharlesAddis ma maledizioni / ncurses non funzionano solo in C ++?
Xam,

Risposte:


783

Se si stampa solo "\r"sulla console, il cursore torna all'inizio della riga corrente e quindi è possibile riscriverlo. Questo dovrebbe fare il trucco:

for(int i = 0; i < 100; ++i)
{
    Console.Write("\r{0}%   ", i);
}

Nota i pochi spazi dopo il numero per assicurarti che tutto ciò che c'era prima fosse cancellato.
Notare anche l'uso di Write()invece di WriteLine()poiché non si desidera aggiungere un "\ n" alla fine della riga.


7
per (int i = 0; i <= 100; ++ i) andrà al 100%
Nicolas Tyler,

13
Come gestisci quando la scrittura precedente era più lunga della nuova scrittura? C'è un modo per ottenere la larghezza della console e riempire la linea di spazi, forse?
Ha disegnato Chapin l'

6
@druciferre In cima alla mia testa mi vengono in mente due risposte alla tua domanda. Entrambi implicano prima di salvare l'output corrente come stringa e di riempirlo con una quantità fissa di caratteri come questo: Console.Write ("\ r {0}", strOutput.PadRight (nPaddingCount, '')); "NPaddingCount" può essere un numero impostato dall'utente oppure è possibile tenere traccia dell'output precedente e impostare nPaddingCount come differenza di lunghezza tra l'output precedente e corrente più la lunghezza dell'output corrente. Se nPaddingCount è negativo, non dovresti usare PadRight a meno che tu non faccia abs (prec.len - curr.len).
John Odom,

1
@malgm Codice ben organizzato. Se una qualsiasi dozzina di thread è in grado di scrivere sulla console ogni volta che lo desidera, ciò ti darà problemi indipendentemente dal fatto che tu stia scrivendo o meno nuove righe.
Segna il

2
@JohnOdom devi solo mantenere la lunghezza di output precedente (non imbottita), e poi inserirla come primo argomento in PadRight(salvare la stringa non imbottita, o lunghezza, prima, ovviamente).
Jesper Matthiesen,

254

È possibile utilizzare Console.SetCursorPositionper impostare la posizione del cursore e quindi scrivere nella posizione corrente.

Ecco un esempio che mostra un semplice "spinner":

static void Main(string[] args)
{
    var spin = new ConsoleSpinner();
    Console.Write("Working....");
    while (true) 
    {
        spin.Turn();
    }
}

public class ConsoleSpinner
{
    int counter;

    public void Turn()
    {
        counter++;        
        switch (counter % 4)
        {
            case 0: Console.Write("/"); counter = 0; break;
            case 1: Console.Write("-"); break;
            case 2: Console.Write("\\"); break;
            case 3: Console.Write("|"); break;
        }
        Thread.Sleep(100);
        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
    }
}

Nota che dovrai assicurarti di sovrascrivere qualsiasi output esistente con nuovo output o spazi vuoti.

Aggiornamento: poiché è stato criticato il fatto che l'esempio sposta il cursore indietro di un solo carattere, lo aggiungerò per un chiarimento: l'uso di SetCursorPositionte può impostare il cursore su qualsiasi posizione nella finestra della console.

Console.SetCursorPosition(0, Console.CursorTop);

imposterà il cursore all'inizio della riga corrente (oppure puoi usarlo Console.CursorLeft = 0direttamente).


8
Il problema potrebbe essere risolto usando \ r, ma l'uso SetCursorPosition(o CursorLeft) consente una maggiore flessibilità, ad es. Non scrivere all'inizio della riga, spostarsi verso l'alto nella finestra, ecc. Quindi è un approccio più generale che può essere usato ad es. barre di avanzamento personalizzate o grafica ASCII.
Dirk Vollmar,

14
+1 per essere prolisso e andare oltre e oltre la chiamata del dovere. Roba buona grazie.
Copas,

1
+1 per mostrare un modo diverso di farlo. Tutti gli altri hanno mostrato \ r, e se l'OP sta semplicemente aggiornando una percentuale, con questo può semplicemente aggiornare il valore senza dover riscrivere l'intera riga. L'OP non ha mai effettivamente detto che voleva spostarsi all'inizio della riga, solo che voleva aggiornare qualcosa sulla stessa riga del cursore.
Andy,

1
La maggiore flessibilità di SetCursorPosition ha un costo di un po 'di velocità e un notevole sfarfallio del cursore se il loop è abbastanza lungo da essere notato dall'utente. Vedi il mio commento di prova qui sotto.
Kevin,

5
Conferma anche che la lunghezza della linea non causa il passaggio alla console della riga successiva o potresti comunque riscontrare problemi con il contenuto che scorre lungo la finestra della console.
Mandrake,

84

Finora abbiamo tre alternative in competizione per come fare questo:

Console.Write("\r{0}   ", value);                      // Option 1: carriage return
Console.Write("\b\b\b\b\b{0}", value);                 // Option 2: backspace
{                                                      // Option 3 in two parts:
    Console.SetCursorPosition(0, Console.CursorTop);   // - Move cursor
    Console.Write(value);                              // - Rewrite
}

Ho sempre usato Console.CursorLeft = 0una variante della terza opzione, quindi ho deciso di fare alcuni test. Ecco il codice che ho usato:

public static void CursorTest()
{
    int testsize = 1000000;

    Console.WriteLine("Testing cursor position");
    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < testsize; i++)
    {
        Console.Write("\rCounting: {0}     ", i);
    }
    sw.Stop();
    Console.WriteLine("\nTime using \\r: {0}", sw.ElapsedMilliseconds);

    sw.Reset();
    sw.Start();
    int top = Console.CursorTop;
    for (int i = 0; i < testsize; i++)
    {
        Console.SetCursorPosition(0, top);        
        Console.Write("Counting: {0}     ", i);
    }
    sw.Stop();
    Console.WriteLine("\nTime using CursorLeft: {0}", sw.ElapsedMilliseconds);

    sw.Reset();
    sw.Start();
    Console.Write("Counting:          ");
    for (int i = 0; i < testsize; i++)
    {        
        Console.Write("\b\b\b\b\b\b\b\b{0,8}", i);
    }

    sw.Stop();
    Console.WriteLine("\nTime using \\b: {0}", sw.ElapsedMilliseconds);
}

Sulla mia macchina, ottengo i seguenti risultati:

  • Spazi posteriori: 25,0 secondi
  • Ritorni a capo : 28,7 secondi
  • SetCursorPosition: 49.7 secondi

Inoltre, ha SetCursorPositioncausato uno sfarfallio evidente che non ho osservato con nessuna delle alternative. Quindi, la morale è usare backspaces o ritorni a capo quando possibile , e grazie per avermi insegnato un modo più veloce per farlo, SO!


Aggiornamento : nei commenti, Joel suggerisce che SetCursorPosition è costante rispetto alla distanza spostata mentre gli altri metodi sono lineari. Ulteriori test confermano che questo è il caso, tuttavia il tempo costante e lento è ancora lento. Nei miei test, scrivere una lunga serie di backspaces sulla console è più veloce di SetCursorPosition fino a circa 60 caratteri. Quindi il backspace è più veloce per la sostituzione di parti della riga più corte di 60 caratteri (o giù di lì), e non lampeggia, quindi sopporterò il mio avallo iniziale di \ b su \ r e SetCursorPosition.


4
L'efficienza dell'operazione in questione non dovrebbe davvero importare. Dovrebbe accadere tutto troppo in fretta per essere notato dall'utente. La microptimizzazione non necessaria è negativa.
Malfist,

@Malfist: a seconda della lunghezza del loop, l'utente può notarlo o meno. Come ho aggiunto nella modifica sopra (prima che vedessi il tuo commento), SetCursorPosition ha introdotto lo sfarfallio e impiega quasi il doppio delle altre opzioni.
Kevin,

1
Concordo sul fatto che si tratta di una micro-ottimizzazione (eseguirla un milione di volte e impiegare 50 secondi è ancora una quantità molto piccola di tempo), +1 per i risultati e potrebbe sicuramente essere molto utile sapere.
Andy,

6
Il benchmark è fondamentalmente imperfetto. È possibile che il tempo SetCursorPosition () sia lo stesso indipendentemente da quanto si sposta il cursore, mentre le altre opzioni variano in base al numero di caratteri che la console deve elaborare.
Joel Coehoorn,

1
Questa è una bella sintesi delle diverse opzioni disponibili. Tuttavia, vedo anche sfarfallio quando si utilizza \ r. Con \ b non c'è ovviamente sfarfallio perché il testo della correzione ("Conteggio:") non viene riscritto. Sfarfallerai anche se aggiungi \ b aggiuntivo e riscrivi il testo della correzione come succede con \ b e SetCursorPosition. Per quanto riguarda l'osservazione di Joel: Joel ha fondamentalmente ragione, tuttavia supererà comunque SetCursorPosition su linee molto lunghe, ma la differenza diminuisce.
Dirk Vollmar,

27

È possibile utilizzare la sequenza di escape \ b (backspace) per eseguire il backup di un determinato numero di caratteri sulla riga corrente. Questo sposta solo la posizione corrente, non rimuove i caratteri.

Per esempio:

string line="";

for(int i=0; i<100; i++)
{
    string backup=new string('\b',line.Length);
    Console.Write(backup);
    line=string.Format("{0}%",i);
    Console.Write(line);
}

Qui, la riga è la riga percentuale da scrivere sulla console. Il trucco è generare il numero corretto di \ b caratteri per l'output precedente.

Il vantaggio di questo nel corso del \ r approccio è che se funziona anche se l'output percentuale non si trova all'inizio della riga.


1
+1, questo risulta essere il metodo più veloce presentato (vedi il mio commento di prova di seguito)
Kevin,

19

\rviene utilizzato per questi scenari.
\r rappresenta un ritorno a capo, il che significa che il cursore ritorna all'inizio della riga.
Ecco perché Windows utilizza \n\rcome nuovo indicatore di linea.
\nti sposta lungo una linea e \rti riporta all'inizio della linea.


22
Tranne che in realtà è \ r \ n.
Joel Mueller

14

Dovevo solo giocare con la ConsoleSpinnerclasse del divo . Il mio non è per nulla conciso, ma non mi è sembrato che gli utenti di quella classe debbano scrivere il proprio while(true)loop. Sto girando per un'esperienza più simile a questa:

static void Main(string[] args)
{
    Console.Write("Working....");
    ConsoleSpinner spin = new ConsoleSpinner();
    spin.Start();

    // Do some work...

    spin.Stop(); 
}

E l'ho realizzato con il codice qui sotto. Dal momento che non voglio che il mio Start()metodo si blocchi, non voglio che l'utente si debba preoccupare di scrivere un while(spinFlag)ciclo simile e voglio consentire a più spinner allo stesso tempo che ho dovuto generare un thread separato per gestire il Filatura. Ciò significa che il codice deve essere molto più complicato.

Inoltre, non ho fatto molto multi-threading, quindi è possibile (probabilmente anche) che ho lasciato un bug sottile o tre in là. Ma sembra funzionare abbastanza bene finora:

public class ConsoleSpinner : IDisposable
{       
    public ConsoleSpinner()
    {
        CursorLeft = Console.CursorLeft;
        CursorTop = Console.CursorTop;  
    }

    public ConsoleSpinner(bool start)
        : this()
    {
        if (start) Start();
    }

    public void Start()
    {
        // prevent two conflicting Start() calls ot the same instance
        lock (instanceLocker) 
        {
            if (!running )
            {
                running = true;
                turner = new Thread(Turn);
                turner.Start();
            }
        }
    }

    public void StartHere()
    {
        SetPosition();
        Start();
    }

    public void Stop()
    {
        lock (instanceLocker)
        {
            if (!running) return;

            running = false;
            if (! turner.Join(250))
                turner.Abort();
        }
    }

    public void SetPosition()
    {
        SetPosition(Console.CursorLeft, Console.CursorTop);
    }

    public void SetPosition(int left, int top)
    {
        bool wasRunning;
        //prevent other start/stops during move
        lock (instanceLocker)
        {
            wasRunning = running;
            Stop();

            CursorLeft = left;
            CursorTop = top;

            if (wasRunning) Start();
        } 
    }

    public bool IsSpinning { get { return running;} }

    /* ---  PRIVATE --- */

    private int counter=-1;
    private Thread turner; 
    private bool running = false;
    private int rate = 100;
    private int CursorLeft;
    private int CursorTop;
    private Object instanceLocker = new Object();
    private static Object console = new Object();

    private void Turn()
    {
        while (running)
        {
            counter++;

            // prevent two instances from overlapping cursor position updates
            // weird things can still happen if the main ui thread moves the cursor during an update and context switch
            lock (console)
            {                  
                int OldLeft = Console.CursorLeft;
                int OldTop = Console.CursorTop;
                Console.SetCursorPosition(CursorLeft, CursorTop);

                switch (counter)
                {
                    case 0: Console.Write("/"); break;
                    case 1: Console.Write("-"); break;
                    case 2: Console.Write("\\"); break;
                    case 3: Console.Write("|"); counter = -1; break;
                }
                Console.SetCursorPosition(OldLeft, OldTop);
            }

            Thread.Sleep(rate);
        }
        lock (console)
        {   // clean up
            int OldLeft = Console.CursorLeft;
            int OldTop = Console.CursorTop;
            Console.SetCursorPosition(CursorLeft, CursorTop);
            Console.Write(' ');
            Console.SetCursorPosition(OldLeft, OldTop);
        }
    }

    public void Dispose()
    {
        Stop();
    }
}

Bella modifica, anche se il codice di esempio non è mio. È tratto dal blog di Brad Abrams (vedi il link nella mia risposta). Penso che sia stato appena scritto come un semplice esempio che dimostra SetCursorPosition. A proposito, sono decisamente sorpreso (in modo positivo) dalla discussione iniziata su quello che pensavo fosse solo un semplice esempio. Ecco perché adoro questo sito :-)
Dirk Vollmar,

4

L'uso esplicito di un ritorno a capo (\ r) all'inizio della riga anziché (implicitamente o esplicitamente) utilizzando una nuova riga (\ n) alla fine dovrebbe ottenere ciò che desideri. Per esempio:

void demoPercentDone() {
    for(int i = 0; i < 100; i++) {
        System.Console.Write( "\rProcessing {0}%...", i );
        System.Threading.Thread.Sleep( 1000 );
    }
    System.Console.WriteLine();    
}

-1, la domanda chiede C #, lo riscrivo in C # e lo cambi di nuovo in F #
Malfist,

Sembra un conflitto di modifica piuttosto che lui che cambia il tuo C # in F #. Il suo cambiamento è stato un minuto dopo il tuo, e si è concentrato sullo sprintf.
Andy,

Grazie per la modifica. Tendo a usare la modalità interattiva F # per testare le cose e ho pensato che le parti importanti fossero le chiamate BCL, che sono le stesse in C #.
James Hugard,

3
    public void Update(string data)
    {
        Console.Write(string.Format("\r{0}", "".PadLeft(Console.CursorLeft, ' ')));
        Console.Write(string.Format("\r{0}", data));
    }

1

Dai documenti della console in MSDN:

È possibile risolvere questo problema impostando la proprietà TextWriter.NewLine della proprietà Out o Error su un'altra stringa di terminazione di riga. Ad esempio, l'istruzione C #, Console.Error.NewLine = "\ r \ n \ r \ n" ;, imposta la stringa di terminazione della riga per il flusso di output dell'errore standard su due sequenze di ritorno a capo e avanzamento riga. Quindi è possibile chiamare esplicitamente il metodo WriteLine dell'oggetto del flusso di output degli errori, come nell'istruzione C #, Console.Error.WriteLine ();

Quindi - ho fatto questo:

Console.Out.Newline = String.Empty;

Quindi sono in grado di controllare l'output da solo;

Console.WriteLine("Starting item 1:");
    Item1();
Console.WriteLine("OK.\nStarting Item2:");

Un altro modo per arrivarci.


Potresti semplicemente utilizzare Console.Write () per lo stesso scopo, senza ridefinire la proprietà NewLine ...
Radosław Gers,

1

Funziona se vuoi che la generazione dei file appaia interessante.

                int num = 1;
                var spin = new ConsoleSpinner();
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write("");
                while (true)
                {
                    spin.Turn();
                    Console.Write("\r{0} Generating Files ", num);
                    num++;
                }

E questo è il metodo che ho ottenuto da qualche risposta qui sotto e l'ho modificato

public class ConsoleSpinner
    {
        int counter;

        public void Turn()
        {
            counter++;
            switch (counter % 4)
            {
                case 0: Console.Write("."); counter = 0; break;
                case 1: Console.Write(".."); break;
                case 2: Console.Write("..."); break;
                case 3: Console.Write("...."); break;
                case 4: Console.Write("\r"); break;
            }
            Thread.Sleep(100);
            Console.SetCursorPosition(23, Console.CursorTop);
        }
    }

0

Eccone un altro: D

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Working... ");
        int spinIndex = 0;
        while (true)
        {
            // obfuscate FTW! Let's hope overflow is disabled or testers are impatient
            Console.Write("\b" + @"/-\|"[(spinIndex++) & 3]);
        }
    }
}

0

Se si desidera aggiornare una riga, ma le informazioni sono troppo lunghe per essere visualizzate su una riga, potrebbero essere necessarie alcune nuove righe. Ho riscontrato questo problema e di seguito è riportato un modo per risolverlo.

public class DumpOutPutInforInSameLine
{

    //content show in how many lines
    int TotalLine = 0;

    //start cursor line
    int cursorTop = 0;

    // use to set  character number show in one line
    int OneLineCharNum = 75;

    public void DumpInformation(string content)
    {
        OutPutInSameLine(content);
        SetBackSpace();

    }
    static void backspace(int n)
    {
        for (var i = 0; i < n; ++i)
            Console.Write("\b \b");
    }

    public  void SetBackSpace()
    {

        if (TotalLine == 0)
        {
            backspace(OneLineCharNum);
        }
        else
        {
            TotalLine--;
            while (TotalLine >= 0)
            {
                backspace(OneLineCharNum);
                TotalLine--;
                if (TotalLine >= 0)
                {
                    Console.SetCursorPosition(OneLineCharNum, cursorTop + TotalLine);
                }
            }
        }

    }

    private void OutPutInSameLine(string content)
    {
        //Console.WriteLine(TotalNum);

        cursorTop = Console.CursorTop;

        TotalLine = content.Length / OneLineCharNum;

        if (content.Length % OneLineCharNum > 0)
        {
            TotalLine++;

        }

        if (TotalLine == 0)
        {
            Console.Write("{0}", content);

            return;

        }

        int i = 0;
        while (i < TotalLine)
        {
            int cNum = i * OneLineCharNum;
            if (i < TotalLine - 1)
            {
                Console.WriteLine("{0}", content.Substring(cNum, OneLineCharNum));
            }
            else
            {
                Console.Write("{0}", content.Substring(cNum, content.Length - cNum));
            }
            i++;

        }
    }

}
class Program
{
    static void Main(string[] args)
    {

        DumpOutPutInforInSameLine outPutInSameLine = new DumpOutPutInforInSameLine();

        outPutInSameLine.DumpInformation("");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");


        outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");

        //need several lines
        outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");

        outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbb");

    }
}

0

stavo cercando la stessa soluzione in vb.net e ho trovato questo ed è fantastico.

tuttavia, come suggerito da @JohnOdom un modo migliore per gestire lo spazio vuoto se quello precedente è più grande di quello attuale ..

faccio una funzione in vb.net e ho pensato che qualcuno potesse essere aiutato ..

ecco il mio codice:

Private Sub sPrintStatus(strTextToPrint As String, Optional boolIsNewLine As Boolean = False)
    REM intLastLength is declared as public variable on global scope like below
    REM intLastLength As Integer
    If boolIsNewLine = True Then
        intLastLength = 0
    End If
    If intLastLength > strTextToPrint.Length Then
        Console.Write(Convert.ToChar(13) & strTextToPrint.PadRight(strTextToPrint.Length + (intLastLength - strTextToPrint.Length), Convert.ToChar(" ")))
    Else
        Console.Write(Convert.ToChar(13) & strTextToPrint)
    End If
    intLastLength = strTextToPrint.Length
End Sub

Qui è possibile utilizzare la funzione di VB di una variabile locale statica: Static intLastLength As Integer.
Mark Hurd,

0

Stavo cercando questo per vedere se la soluzione che ho scritto potesse essere ottimizzata per la velocità. Quello che volevo era un conto alla rovescia, non solo l'aggiornamento della riga corrente. Ecco cosa mi è venuto in mente. Potrebbe essere utile a qualcuno

            int sleepTime = 5 * 60;    // 5 minutes

            for (int secondsRemaining = sleepTime; secondsRemaining > 0; secondsRemaining --)
            {
                double minutesPrecise = secondsRemaining / 60;
                double minutesRounded = Math.Round(minutesPrecise, 0);
                int seconds = Convert.ToInt32((minutesRounded * 60) - secondsRemaining);
                Console.Write($"\rProcess will resume in {minutesRounded}:{String.Format("{0:D2}", -seconds)} ");
                Thread.Sleep(1000);
            }
            Console.WriteLine("");

0

Ispirato alla soluzione @ E.Lahu, l'implementazione di un progresso barra con percentuale.

public class ConsoleSpinner
{
    private int _counter;

    public void Turn(Color color, int max, string prefix = "Completed", string symbol = "■",int position = 0)
    {
        Console.SetCursorPosition(0, position);
        Console.Write($"{prefix} {ComputeSpinner(_counter, max, symbol)}", color);
        _counter = _counter == max ? 0 : _counter + 1;
    }

    public string ComputeSpinner(int nmb, int max, string symbol)
    {
        var spinner = new StringBuilder();
        if (nmb == 0)
            return "\r ";

        spinner.Append($"[{nmb}%] [");
        for (var i = 0; i < max; i++)
        {
            spinner.Append(i < nmb ? symbol : ".");
        }

        spinner.Append("]");
        return spinner.ToString();
    }
}


public static void Main(string[] args)
    {
        var progressBar= new ConsoleSpinner();
        for (int i = 0; i < 1000; i++)
        {
            progressBar.Turn(Color.Aqua,100);
            Thread.Sleep(1000);
        }
    }

0

Ecco la mia opinione sulle risposte di s soosh e 0xA3. Può aggiornare la console con i messaggi utente durante l'aggiornamento dello spinner e ha anche un indicatore di tempo trascorso.

public class ConsoleSpiner : IDisposable
{
    private static readonly string INDICATOR = "/-\\|";
    private static readonly string MASK = "\r{0} {1:c} {2}";
    int counter;
    Timer timer;
    string message;

    public ConsoleSpiner() {
        counter = 0;
        timer = new Timer(200);
        timer.Elapsed += TimerTick;
    }

    public void Start() {
        timer.Start();
    }

    public void Stop() {
        timer.Stop();
        counter = 0;
    }

    public string Message {
        get { return message; }
        set { message = value; }
    }

    private void TimerTick(object sender, ElapsedEventArgs e) {
        Turn();
    }

    private void Turn() {
        counter++;
        var elapsed = TimeSpan.FromMilliseconds(counter * 200);
        Console.Write(MASK, INDICATOR[counter % 4], elapsed, this.Message);
    }

    public void Dispose() {
        Stop();
        timer.Elapsed -= TimerTick;
        this.timer.Dispose();
    }
}

l'utilizzo è qualcosa del genere:

class Program
{
    static void Main(string[] args)
    {
        using (var spinner = new ConsoleSpiner())
        {
            spinner.Start();
            spinner.Message = "About to do some heavy staff :-)"
            DoWork();
            spinner.Message = "Now processing other staff".
            OtherWork();
            spinner.Stop();
        }
        Console.WriteLine("COMPLETED!!!!!\nPress any key to exit.");

    }
}

-1

Il SetCursorPositionmetodo funziona in uno scenario multi-thread, in cui gli altri due metodi no

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.