2

我有一个用 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 的消息将被附加到我的当前行,并且光标将被放置到下一行。看这个截图:

问题

正如你猜想的那样,我不想要那个。我希望命令的当前输入始终保留在最后一行,并将所有消息放在该行上方。正如您对此类应用程序所期望的那样。我该如何做到这一点?

4

3 回答 3

5

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

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

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

您需要非常熟悉Windows 控制台

预先警告:这是很多工作。而且可能不值得付出努力。

于 2013-08-05T14:14:09.523 回答
3

这是我的问题的答案:

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();
    }
}
于 2013-08-08T11:59:42.020 回答
0

只是一个想法。您可以使用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();
    }
}
于 2013-08-05T14:16:50.577 回答