【问题标题】:Display string value real time实时显示字符串值
【发布时间】:2014-01-08 20:44:55
【问题描述】:

我正在编写一个控制台程序,我的代码如下所示:

配置.cs

public static class Configuration
{
    public static string Message = "";
}

菜单.cs

class Menu
{
    public static void showMenu()
    {
        Console.Clear();
        Console.WriteLine("1: SOMETHING");
        Console.WriteLine("2: SOMETHING");
        Console.WriteLine("3: SOMETHING");
        Console.WriteLine("SYSTEM MSG: " + Configuration.Message);
        Console.Write("INPUT: ");
    }
}

程序.cs

...
static void Main(string[] args)
{
    ...
    int choice;

    while(true)
    {
        Menu.showMenu();
        choice = Convert.ToInt32(Console.ReadLine());

        switch(choice)
        {
            case 1:
            Configuration.Message = "HELLO!";
            break;

            case 2:
            Configuration.Message = "HI!";
            break;

            case 3:
            Configuration.Message = "WHAT?!";
            break;
        }
    }
}
...

现在,当我更改 Configuration.Message 时,它​​会显示在菜单上,因为 showMenu 方法会清除控制台并再次显示字符串。

但我想做的是没有 Clear 方法,我想实时显示 Configuration.Message。我在想使用 Timer 并每秒刷新一次菜单,但效率不高(感觉像作弊)。我该怎么做?

【问题讨论】:

  • 控制台消息和显示实时字符串不是兼容的想法。 Winforms 或 WPF 应用程序可以通过用户输入实时显示,因为您有多个线程。控制台确实不是为此而构建的。
  • @paqogomez 不是多线程使它在其他类型的 GUI 中工作,而是你有完全不同的媒体来显示输出和收集输入。控制台将两者混合在一起的事实是导致问题的原因。
  • 请注意,控制台/终端输入/输出为人们工作了很长时间......我认为这里的问题是 OP 依赖于控制台的绝对默认行为,这确实很难混合输入和输出 - 接管输入/输出(即使只是使用Console.SetCursorPosition 打印到特定位置)将使其成为可能。

标签: c# multithreading real-time


【解决方案1】:

当您写入Console 时,写入操作从当前光标位置开始。所以...

System.Console类的属性和方法,特别是:

  • CursorLeft 获取或设置光标所在的列位置
  • CursorTop 获取或设置光标所在行位置
  • SetCursorPosition( int left , int top ) 设置行和列位置。

在写入每个字符时,光标向右移动一个位置,当光标移过BufferWidth 列时,会换行到下一行(例如,如果您的控制台缓冲区宽度为 80 列,则写入第 80 列column 会将列移到缓冲区之外(第 81 列),因此光标将移动到下一行的第 1 列。

对于您想做的事情,您还可以查看 P/Invoking 本机 Win32 游标方法,或使用 *nix 的 curses(3) 和 Gnu 的 ncurses(3) 的 .Net 派生之一:

【讨论】:

  • +1 这当然是功能齐全的方法。我强烈建议您确保所有控制台交互都在同一个线程中完成。无论您选择哪种解决方案,这都将确保您能够创造最佳的用户体验。
【解决方案2】:

我建议,如果需要这样的功能,最好看看像 WPF 这样的 UI 技术。但是,话虽这么说,也许这会做你想要的。每次设置消息时显示菜单。我认为在使用控制台时没有办法将变量绑定到控制台上的某些消息。

    public static class Configuration
    {
        private static string _message;
        public static string Message 
        { 
            get
            {
                return _message;
            }
            set
            {
                _message = value;
                Menu.showMenu();
            }
        }
    }

编辑:要使用属性更改事件来实现这一点,您可以执行类似的操作。注意,我没有实现INotifyPropertyChanged 来保留静态类。

class Program
    {
        static void Main(string[] args)
        {
            Configuration.PropertyChanged += (sender, e) =>
            {
                Menu.showMenu();
            };
            int choice;

            while (true)
            {
                Menu.showMenu();
                choice = Convert.ToInt32(Console.ReadLine());

                switch (choice)
                {
                    case 1:
                        Configuration.Message = "HELLO!";
                        break;

                    case 2:
                        Configuration.Message = "HI!";
                        break;

                    case 3:
                        Configuration.Message = "WHAT?!";
                        break;
                }
            }
        }
    }

    class Menu
    {
        public static void showMenu()
        {
            Console.Clear();
            Console.WriteLine("1: SOMETHING");
            Console.WriteLine("2: SOMETHING");
            Console.WriteLine("3: SOMETHING");
            Console.WriteLine("SYSTEM MSG: " + Configuration.Message);
            Console.Write("INPUT: ");
        }
    }

    public static class Configuration 
    {
        public static event PropertyChangedEventHandler PropertyChanged;

        private static string _message;
        public static string Message
        {
            get
            {
                return _message;
            }
            set
            {
                if (value != _message)
                {
                    _message = value;
                    NotifyPropertyChanged(property: _message);
                }
            }
        }

        private static void NotifyPropertyChanged(object property, String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(property, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

【讨论】:

  • +1。 Menu 绝对应该是依赖,而不是静态调用......甚至可以实现并连接 INotifyPropertyChanged。但可以作为起点。
  • @AlexeiLevenkov 我同意INotifyPropertyChanged 会是一种更简洁的方法,尤其是如果Configuration 上还有更多成员可以对消息进行分类。
  • 在使用控制台时,尤其是在使用readLine 时,您应该非常小心地控制您的写入,以免它们在读取时发生。将调用写入控制台的showMenu 放在Configuration 类中会破坏此模型并混淆将文本写入控制台的流程。不推荐。
  • @ErickRobertson 这是一个很好的观点。我的建议和你一样,如果需要这样的功能,最好看看像 WPF 这样的 UI 技术。
  • @AlexeiLevenkov 我使用PropertyChangedEvent添加了配置类的编辑
【解决方案3】:

使菜单在用户按 Enter 键时出现。

除非响应用户的输入,否则写入控制台不是一个好主意。这样做的原因是您可能会在他们中间写入控制台,输入他们想要的行。然后他们的文本和退格键将变得不同步,用户将难以理解发生了什么。

我的建议是添加另一个选项,这样用户就可以直接点击ENTER 而无需选择,它将重新显示菜单而无需清除。这将允许用户通过点击ENTER 而不选择选项来决定他们想要实时刷新的时间。

如果您真的想要一种更实时的方法,并且想将其与用户输入混合,我建议控制台不是提供此解决方案的好方法。

【讨论】:

    猜你喜欢
    • 2021-11-04
    • 2015-06-28
    • 2018-05-31
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多