Search code examples
c#timerconsole-application

C# console basic UI with timer


I am making a basic Console application (unfortunately this is a must) that shows the time and a very basic interface where a user can enter an option. When they do, the UI updates with relevant new data to display and allows further input and so on. All the while, a live clock with seconds is shown at the top.

What I am basically doing is redrawing the whole UI every second and attempting to listen to the user input to direct how the UI is drawn next time around. How do I manage the user input while redrawing the UI? Is there a better way?

Here is the whole (very cut down verion of) program:

using System;
using System.Diagnostics;
using System.Timers;

namespace TimerTest
{
    class Program
    {
        static bool useStartUI = false;
        static string currentInput = "";
        static Timer aTimer = new System.Timers.Timer();
        static void Main(string[] args)
        {
            aTimer.Elapsed += new ElapsedEventHandler(DrawUI);
            aTimer.Interval = 1000;
            aTimer.Enabled = true;
            Console.ReadLine();
            currentInput = Console.ReadLine();
        }
        static void DrawUI(object source, ElapsedEventArgs e)
        {
            Debug.WriteLine("currentInput = " + currentInput);
            if (currentInput == "A")
            {
                useStartUI = true;
            } else
            {
                useStartUI = false;
            }
            if (!useStartUI)
            {
                DisplayStartUI();
            }
            else
            {
                DisplayCurrentUI();
            }
        }
        private static void DisplayStartUI()
        {
            Console.Clear();
            Console.WriteLine("DisplayStartUI - " +     DateTime.Now.ToString("HH:mm:ss tt"));
            Console.WriteLine("Press 'B' to switch to CurrentUI");
            Console.ReadLine();
            currentInput = Console.ReadLine();
        }
        private static void DisplayCurrentUI()
        {
            Console.Clear();
            Console.WriteLine("DisplayCurrentUI - " +     DateTime.Now.ToString("HH:mm:ss tt"));
            Console.WriteLine("Press 'A' to switch to StartUI");
            Console.ReadLine();
            currentInput = Console.ReadLine();
        }
    }
}

At the moment I have the Console.ReadLine(); right after the timer is fired, if I don't then the application opens and closes straight away. The other two Console.ReadLine(); are ignored completely but it is at these points I would have expected user input to be recorded.


Solution

  • Seems I was over thinking this and @elgonzo pointed me in the right direction. I now just have the timer display on one line and clear other lines as and when I need them. I have a basic working example that I will expand my main program into. It appears to do exactly what I need (obviously missing validation and functionality) please comment if this can be improved upon:

    using System;
    using System.Diagnostics;
    using System.Timers;
    
    namespace TimerTest
    {
        class Program
        {
            static bool appOpen = true;
            static bool useStartUI = false;
            static string currentInput = "";
            static Timer aTimer = new System.Timers.Timer();
            static void Main(string[] args)
            {
                Console.WriteLine("Main - " + DateTime.Now.ToString("HH:mm:ss tt"));
                aTimer.Elapsed += new ElapsedEventHandler(DrawClock);
                aTimer.Interval = 1000;
                aTimer.Enabled = true;
    
                while (appOpen) // to keep the application running and give a possible exit - will expand this
                {
                    DrawUI();
                }
            }
            #region UI region
            static void DrawClock(object source, ElapsedEventArgs e)
            {
                Console.SetCursorPosition(0, 0);
                Console.WriteLine("DrawClock - " + DateTime.Now.ToString("HH:mm:ss     tt"));
                Console.SetCursorPosition(0, 7);
            }
            static void DrawUI()
            {
                Debug.WriteLine("currentInput = " + currentInput);
                if (currentInput == "A" || currentInput == "a")
                {
                    useStartUI = true;
                }
                else if (currentInput == "B" || currentInput == "b")
                {
                    useStartUI = false;
                }
                if (useStartUI)
                {
                    DisplayStartUI();
                }
                else
                {
                    DisplayCurrentUI();
                }
            }
            private static void DisplayStartUI()
            {
                CleanUI();
                Console.WriteLine("DisplayStartUI");
                Console.WriteLine("Press 'B' to switch to CurrentUI");
    
                ConsoleKeyInfo keyPressed = Console.ReadKey();
                Console.SetCursorPosition(0, 7);
                Console.WriteLine("You pressed {0}", keyPressed.KeyChar);
                currentInput = keyPressed.KeyChar.ToString();
                if (keyPressed.KeyChar.ToString() == "b")
                {
                    DrawUI();
                }
            }
            private static void DisplayCurrentUI()
            {
                CleanUI();
                Console.WriteLine("DisplayCurrentUI");
                Console.WriteLine("Press 'A' to switch to StartUI");
                ConsoleKeyInfo keyPressed = Console.ReadKey();
                Console.SetCursorPosition(0, 7);
                Console.WriteLine("You pressed {0}", keyPressed.KeyChar);
                currentInput = keyPressed.KeyChar.ToString();
                if (keyPressed.KeyChar.ToString() == "a")
                {
                    DrawUI();
                }
            }
            #endregion
            #region functional methods
            public static void CleanUI()
            {
                Console.SetCursorPosition(0, 5);
                ClearCurrentConsoleLine();
                Console.SetCursorPosition(0, 6);
                ClearCurrentConsoleLine();
                Console.SetCursorPosition(0, 7);
                ClearCurrentConsoleLine();
                Console.SetCursorPosition(0, 5);
            }
            public static void ClearCurrentConsoleLine()
            {
                int currentLineCursor = Console.CursorTop;
                Console.SetCursorPosition(0, Console.CursorTop);
                Console.Write(new string(' ', Console.WindowWidth));
                Console.SetCursorPosition(0, currentLineCursor);
            }
            #endregion
        }
    }