Search code examples
c#timerconsole

Run other code while timer is running in c#


I am making a C# console maths test where the user answers maths questions

I am trying to add a timer to the test, but I can't make my timer run at the same time as my other code

Here is an example of my code:

class Program
{
    public static OtherCode()
    {
        \\*other code for test
    }
    public class Timer
    {
        public static int Timers(int timeLeft)
        {
            do
            {
                Console.Write("\rtimeLeft: {0} ", timeLeft);
                timeLeft--;
                Thread.Sleep(1000);
            } while (timeLeft > 0);
            Console.Write(Environment.NewLine);
            return timeLeft;
        }
    }
    
    public static void Main(string[] args)
    {
        int numberOfSeconds = 30;
        Timer.Timers(numberOfSeconds);

        \\other code
        OtherCode();
    }
}

I would like my timer to be running at the top of the console and the maths questions to be asked underneath like this except the question should be on a newline: enter image description here

Any help appreciated!

UPDATE

When I add Console.SetCursorPosition() to my code like so:

do
    {
        Console.SetCursorPosition(0, 9);        
        Console.Write("\rtimeLeft: {0} ", timeLeft);
        timeLeft--;
        Thread.Sleep(1000);
    } while (timeLeft > 0);

My code won't move the timer but when I type the answer to one of my maths questions it makes me type it on the same line as the timer like this: enter image description here


Solution

  • In order to have a status message that stays at the bottom of the console you need a way to manipulate the screen buffer so you continuously overwrite your status message.

    The Console.SetCursorPos can be used for this and is usefull in more advanced scenarios, but I think you can get by with simply using \r to reset the cursor to the beginning of the line.

    Proof of consept:

    using System;
    
    namespace consoletimer
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hello World!");
                int numberOfSeconds = 300;
                var thread = new System.Threading.Thread(()=> PrintStatusMessage(numberOfSeconds));
                thread.Start();
                int n = 5;
                while(n-- > 0){
                    WriteToScreen("Example text", false);
                    ReadInput();
                    System.Threading.Thread.Sleep(2000);
                }
            }
    
            static void PrintStatusMessage(int numberOfSeconds){
                var whenToStop = DateTime.Now.AddSeconds(numberOfSeconds);
                while(DateTime.Now < whenToStop){
                    var timeLeft = (whenToStop-DateTime.Now).ToString(@"hh\:mm\:ss");
                    WriteToScreen($"Time Remaining: {timeLeft}", true);
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            static string ReadInput(){
                string input = Console.ReadLine();
                Console.Write(new string(' ',100));
                Console.CursorLeft = 0;
                return input;
            }
    
            static object lockObject = new object();
    
            static void WriteToScreen(string message, bool resetCursor){
                lock(lockObject){
                    if(resetCursor){
                        int leftPos = Console.CursorLeft;
                        Console.WriteLine();
                        Console.Write(message.PadRight( 50, ' '));
                        Console.CursorTop--;
                        Console.CursorLeft = leftPos;
                    }
                    else{
                        Console.WriteLine(message);
                        Console.Write(new string(' ',100));
                        Console.CursorLeft = 0;
                    }   
                }
            }
        }    
    }
    

    Edit

    We need to clear the next line whenever we write to the console so that we remove the status message that was there previously.