始终将Console.ReadLine保留在最后一行

我有一个用C#编写的应用程序,它通过while(true)循环和Console.ReadLine连续获取用户的命令。

我也有各种后台操作,通过控制台报告。 查看这个简单的例子:

class Program { static void Main(string[] args) { new Messager(1000 * 2.5f); new Messager(1000 * 3); while (true) { Console.ReadLine(); } } } public class Messager { Timer Timer; public Messager(double interval) { this.Timer = new Timer(interval); this.Timer.Elapsed += (sender, e) => { Console.WriteLine("message from " + this.Timer.Interval); }; this.Timer.Start(); } } 

问题是,当我输入命令并且Messager报告回来之前我按下Enter键时,来自Messager的消息将被附加到我当前的行,光标将被放入下一行。 看这个截图:

问题

正如你猜我不想那样。 我希望当前输入的命令始终保持在最后一行,并将所有消息放在该行之上。 正如您对此类应用程序的期望一样。 我如何实现这一目标?

这非常非常困难。 您最终编写自己的控制台输入和输出方法,每个线程都必须调用。 如果任何线程不合作,它就行不通。 但是可以使用Console API。

基本思路是让您的公共输出函数写入控制台屏幕缓冲区,并在代码中滚动缓冲区,而不是让文本流到最后一行并自动滚动。 我记得,你必须解析换行符和其他控制字符的输出,并正确处理它们。

您可以在最后一行使用Console.ReadLine ,但如果用户输入的文本多于单行上的文本,则可能会出现问题。 此外,用户在该行的末尾按Enter键可能会导致它向上滚动。 在这种情况下使用原始控制台输入可能是最好的。

您将希望对Windows控制台非常熟悉。

预先警告:这是很多工作。 也许不值得努力。

这是我的问题的答案:

 class Program { static void Main(string[] args) { new Messager(1000 * 2.5f); new Messager(1000 * 3); while (true) { Console.ReadLine(); } } } public class Messager { Timer Timer; public Messager(double interval) { this.Timer = new Timer(interval); this.Timer.Elapsed += (sender, e) => { int currentTopCursor = Console.CursorTop; int currentLeftCursor = Console.CursorLeft; Console.MoveBufferArea(0, currentTopCursor, Console.WindowWidth, 1, 0, currentTopCursor + 1); Console.CursorTop = currentTopCursor; Console.CursorLeft = 0; Console.WriteLine("message from " + this.Timer.Interval); Console.CursorTop = currentTopCursor +1; Console.CursorLeft = currentLeftCursor; }; this.Timer.Start(); } } 

只是一个想法。 您可以使用Console.CursorTopConsole.CursorLeft属性。

 class Program { static void Main(string[] args) { new Messager(1000 * 2.5f); new Messager(1000 * 3); while (true) { Console.CursorTop = 0; Console.ReadLine(); } } } public class Messager { Timer Timer; static int position = 1; public Messager(double interval) { this.Timer = new Timer(interval); this.Timer.Elapsed += (sender, e) => { lock (this) { var cursorLeft = Console.CursorLeft; Console.CursorLeft = 0; Console.CursorTop = position++; Console.WriteLine("message from " + this.Timer.Interval); Console.CursorTop = 0; Console.CursorLeft = cursorLeft; } }; this.Timer.Start(); } }