3

This is how I keep the console window open now:

private static void Main(string[] args)
{
    // Timers run here

    while(true)
    {
        Console.Read();
    }
}

But it always gets back to me: there must be a better way. The reason that Console.Read() is in an eternal while is because I don't want my program to terminate if by mistake I press enter while it's running and I'm focused on its window.

Any ideas?

Relevant questions that don't answer my question:

Community
  • 1
  • 1
Doug Peters
  • 529
  • 2
  • 8
  • 17
  • You want to keep the console window open while it's doing some work? – Codecat Mar 14 '14 at 19:21
  • This looks like you're keeping the window open *after* it's done with its work. Usually something like a single `Console.ReadLine()` (with a message to "press return to close") is the standard approach to keep a window open until the user dismisses it. – David Mar 14 '14 at 19:22
  • @AngeloGeels Exactly. I want to keep it open until I explicitly close it from the `x` close dialog. – Doug Peters Mar 14 '14 at 19:23
  • @David you are right; I updated the code to fit my case. – Doug Peters Mar 14 '14 at 19:24
  • 2
    You probably want to use multithreading then, yes? – Codecat Mar 14 '14 at 19:26
  • 1
    @DougPeters: Ah, now it makes more sense. You want background tasks to complete before the application closes. In that case I wonder if the overall architecture is in question here. If this should be an "always running" application with timers, then maybe a Windows Service would work better? Or break out the timed components into their own applications and replace the timers with scheduled jobs in the host OS? If they just need to be single-run background tasks then maybe instead of timers use something like parallel tasks and await those tasks at the end? – David Mar 14 '14 at 19:26
  • @AngeloGeels well I use many a timers so yes, my app is multithreaded, however I just want to keep the console window open so I can track each timer's progress and of course for the timers to run in eternity. – Doug Peters Mar 14 '14 at 19:29
  • @DougPeters: `"and of course for the timers to run in eternity"` - That *really* sounds more like the job of a Windows Service. Or perhaps a System Tray application: http://msdn.microsoft.com/en-us/vstudio/bb798029 – David Mar 14 '14 at 19:32
  • @David I need to see real-time statistics from the console so for now I would prefer not to turn this into a service, generally speaking you are right, a service would be ideal for this case. I also cannot break down the timer-controlled components as they interact with each other through the heap. – Doug Peters Mar 14 '14 at 19:33
  • 1
    @DougPeters Is refactoring to use .NET task framework and using `Task.WaitAll()` an option? http://msdn.microsoft.com/en-us/library/dd270695(v=vs.110).aspx – jdphenix Mar 14 '14 at 19:40
  • @jdphenix that's a nice workaround that I wasn't aware of, although I'd rather avoid refactoring at this stage (there are thousands of line already in place). – Doug Peters Mar 14 '14 at 19:57

3 Answers3

4

I assume you want to run tasks on the background, and as such you should just start a thread, like this:

private static void Main(string[] args)
{
    new Thread(new ThreadStart(SomeThreadFunction)).Start();

    while(true)
    {
        Console.Read();
    }
}

static void SomeThreadFunction()
{
  while(true) {
    Console.WriteLine("Tick");
    Thread.Sleep(1000);
  }
}
Codecat
  • 2,213
  • 3
  • 28
  • 39
4

Given the discussions so far in comments, my first recommendation is definitely to create a System Tray application for this. This would allow for user interaction and notifications without having to keep a Console window on the desktop.

Failing that, you could perhaps implement something like a "game loop" in your console. How "real time" do the statistics need to be? One-second delayed maybe? Something like this:

while (true)
{
    Thread.Sleep(1000);
    DisplayCurrentStats();
}

This would pause the main thread (not always recommended, but it is the UI that you're trying to keep open here) and then output the display every second. (If the output is already handled by something else and for whatever reasons shouldn't be moved here, just ignore that part.)

You'd probably still want some way of breaking out of the whole thing. Maybe an escape input:

while (true)
{
    Thread.Sleep(1000);
    DisplayCurrentStats();
    var escape = Console.Read();
    if (IsEscapeCharacter(escape))
        break;
}
OutputGoodByeMessage();

In the IsEscapeCharacter() method you can check if the character read from the Console (if there was one) matches the expected "escape" character. (The esc key seems like a standard choice, though for obscurity you can use anything else in order to try to prevent "accidental escape.") This would allow you to terminate the application cleanly if you need to.

It's still at 1-second delay increments, which isn't ideal. Though even at 1/10-second it's still spending the vast majority of its time sleeping (that is, not consuming computing resources) while providing some decent UI responsiveness (who complains about a 1/10-second delay?):

Thread.Sleep(100);
David
  • 208,112
  • 36
  • 198
  • 279
1

I don't want my program to terminate if by mistake I press enter

You want some thing similar to this:

while (Console.ReadKey(true).Key == ConsoleKey.Enter)
{
    Console.Read();
}

The above code does not quit if you press ENTER key but it quits when you press any oteher keys.

Sudhakar Tillapudi
  • 25,935
  • 5
  • 37
  • 67