Lac*_*her 7 c# console-application
我看过其他一些与这个帖子非常相似的帖子,但他们给出的答案并没有正确回答这个问题.对不起,如果有隐藏的东西,我找不到...
我想使用Console.WriteLine()打印当前Console.ReadLine()之上的内容,例如,我的应用程序打印"Hello world"并启动一个线程(在5秒内)将打印"我等了5秒"在我需要输入内容的行之上,如下所示:
Hello world
Please input something: _
Run Code Online (Sandbox Code Playgroud)
然后5秒钟将通过,它将如下所示:
Hello world
I just waited 5 seconds
Please input something: _
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已经尝试使用Console.SetCursorPosition(0,Console.CursorTop - 1),但这只打印在"请输入内容:_"这一行,如果我使用Console.CursorTop - 2而不是崩溃说"[2]超出范围"(不知道为什么会这样),如果我使用Console.CursorTop - 2,它打印在"请输入内容:_"...所以我的问题是我如何打印上面的内容"请输入一些内容: _"
只是移动光标不够好,问题是你正在插入文本.这是可能的,Console.MoveBufferArea()方法允许您访问控制台的底层屏幕缓冲区,并允许您将文本和属性移动到另一行.
有几个棘手的角落案例.你已经找到的,如果光标位于缓冲区的末尾,你必须强制控制台滚动.并且计时器是一个非常难以解决的问题,如果您可以阻止Console.ReadLine()在计时器的Elapsed事件插入文本的同时移动光标,则只能正确执行此操作.这需要一个lock,你不能在Console.ReadLine()中插入一个锁.
您可以使用一些示例代码来帮助您:
static string TimedReadline(string prompt, int seconds) {
int y = Console.CursorTop;
// Force a scroll if we're at the end of the buffer
if (y == Console.BufferHeight - 1) {
Console.WriteLine();
Console.SetCursorPosition(0, --y);
}
// Setup the timer
using (var tmr = new System.Timers.Timer(1000 * seconds)) {
tmr.AutoReset = false;
tmr.Elapsed += (s, e) => {
if (Console.CursorTop != y) return;
int x = Cursor.Left;
Console.MoveBufferArea(0, y, Console.WindowWidth, 1, 0, y + 1);
Console.SetCursorPosition(0, y);
Console.Write("I just waited {0} seconds", seconds);
Console.SetCursorPosition(x, y + 1);
};
tmr.Enabled = true;
// Write the prompt and obtain the user's input
Console.Write(prompt);
return Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
样品用法:
static void Main(string[] args) {
for (int ix = 0; ix < Console.BufferHeight; ++ix) Console.WriteLine("Hello world");
var input = TimedReadline("Please input something: ", 2);
}
Run Code Online (Sandbox Code Playgroud)
请注意Console.Top属性上的测试,它确保当用户键入太多文本并强制滚动或者Console.ReadLine()在计时器选中的同时完成时,没有任何严重错误.在所有可能的情况下证明它是线程安全的很难做到,当Console.ReadLine()在Elapsed事件处理程序运行的同时水平移动光标时肯定会出现问题.我建议您编写自己的Console.ReadLine()方法,以便插入锁并确信它始终是安全的.
您可以使用回车符(\r或 U+000D)将光标返回到当前行的开头,然后覆盖那里的内容。就像是
// A bunch of spaces to clear the previous output
Console.Write("\r ");
Console.WriteLine("\rI just waited 5 seconds");
Console.Write("Please input something: ");
Run Code Online (Sandbox Code Playgroud)
但是,如果用户已经开始输入,这将不再起作用(因为您可能不会覆盖他们输入的所有内容,并且他们将丢失在屏幕上输入的内容,尽管它仍然存在于内存中。
要正确解决此问题,您实际上需要修改控制台的字符缓冲区。您必须将当前行上方的所有内容向上移动一行,然后插入消息。您可以用来Console.MoveBufferArea向上移动一个区域。然后,您需要保存当前光标位置,将光标移动到上一行的开头,写入消息,然后将光标位置再次重置为保存的位置。
然后你必须希望用户在你写消息时不要打字,因为这会把事情搞砸。不过,我不确定您可以在使用时解决这个问题ReadLine,因为您无法在ReadLine活动时临时锁定某些内容。为了正确解决这个问题,您可能必须编写自己的ReadLine替代方案,该替代方案读取各个按键,并在写入结果字符时锁定一个公共对象,以避免两个线程同时写入控制台。