Xavier Peña
Xavier Peña

Reputation: 7919

Undesired behaviour in Console when printing messages

This problem is probably related to the carriage return character + concurrency, but I can't quite put my finger on it... I have tried plenty of things and I haven't found an answer yet. I would like to at least find a way to correct the error once it has appeared.

Mi executable is a scheduler that prints lines on the command line. At a random moment, the effect shown in the image below (see difference between blue coloured lines) appears and it never leaves. This also appears in a random sequence of events, meaning that in this case it has been after an ADDING but it can also appear after my custom events EXECUTING and ERROR which use other printing functions.

enter image description here

Below you can find the code that exemplifies this behaviour. Note that I am use a token to avoid concurrency.

/// <summary>
/// Console message when the system adds a new execution to the schedule.
/// </summary>
public void PrintAddedExecution(Database.Models.ExecutionSchedule executionDbItem, string messageString)
{
    Threading.Monitor.Enter(ConsoleToken);

    this.ClearLastLineInConsole();
    this.PrintCurrentTime();

    System.Console.BackgroundColor = ConsoleColor.DarkBlue;
    System.Console.WriteLine(" ADDING [ {0} ] : ", messageString);
    System.Console.ResetColor();

    System.Console.WriteLine(string.Format(" > exe='{0}' " + \r\n + " > cmd='{1}'", executionDbItem.exe, executionDbItem.cmd));
    System.Console.WriteLine();

    this.RepeatPrintSystemStatus();

    Threading.Monitor.Exit(ConsoleToken);

}

/// <summary>
/// Clears the last written line in the console ("clear" = "fills it with spaces")
/// </summary>
public void ClearLastLineInConsole()
{
    System.Console.ResetColor();
    System.Console.Write("{0}", \r);

    for (int characterCount = 1; characterCount <= System.Console.WindowWidth - 1; characterCount++) {
        System.Console.Write(" ");
    }

}

/// <summary>
/// Prints the sequence:
/// carriage_return + [ HH:mm ]
/// </summary>
private void PrintCurrentTime()
{

    System.Console.BackgroundColor = ConsoleColor.DarkGray;
    System.Console.ForegroundColor = ConsoleColor.Black;

    System.Console.Write("[ {0:HH:mm:ss} ]", Now);
    System.Console.ResetColor();
    System.Console.Write(" ");

}

Upvotes: 0

Views: 247

Answers (2)

Xavier Pe&#241;a
Xavier Pe&#241;a

Reputation: 7919

So I finally found a way to avoid this error, although I still have no explanation for it.

The solution is that instead of using this kind of code:

Code with problems:

Console.BackgrounColor = ConsoleColor.MyColor;
Console.WriteLine("Write Something In Console");
Console.ResetColor();

Use always this other way:

"Good" code:

Console.BackgrounColor = ConsoleColor.MyColor;
Console.Write("Write Something In Console");
Console.ResetColor();
Console.WriteLine();

Note that the difference is that I am no longer using WriteLine() if a color change is intervening. Just Write().

I "discovered" this effect empirically, so I gave it a try. After lots of hours of testing it seems to work totally fine.

Upvotes: 1

Alessandro D&#39;Andria
Alessandro D&#39;Andria

Reputation: 8878

Try this:

int count = 0;

/// <summary>
/// Console message when the system adds a new execution to the schedule.
/// </summary>
public void PrintAddedExecution(string messageString)
{
    Monitor.Enter(ConsoleToken);

    if (count >= Console.BufferHeight)
    {
        Console.Clear();
        count = 0;
    }

    this.PrintCurrentTime();

    System.Console.BackgroundColor = ConsoleColor.DarkBlue;
    WriteLine(string.Format(" ADDING [ {0} ] : ", messageString));
    System.Console.ResetColor();

    WriteLine(string.Format(" > exe='{0}' ", "executionDbItem.exe"));
    WriteLine(string.Format(" > cmd='{0}'", "executionDbItem.cmd"));
    WriteLine();

    //this.RepeatPrintSystemStatus();

    Monitor.Exit(ConsoleToken);

}

/// <summary>
/// Prints the sequence:
/// carriage_return + [ HH:mm ]
/// </summary>
private void PrintCurrentTime()
{

    System.Console.BackgroundColor = ConsoleColor.DarkGray;
    System.Console.ForegroundColor = ConsoleColor.Black;

    System.Console.Write("[ {0:HH:mm:ss} ]", DateTime.Now);
    System.Console.ResetColor();
    System.Console.Write(" ");

}

// use this method to write a line so you can keep count of the
// total number of written lines
void WriteLine(string s = null)
{
    Console.WriteLine(s);

    count++;
}

The key is to clear the buffer when is full, to test that try to comment the Console.Clear(); line.

Upvotes: 1

Related Questions