有没有办法在属性更改时更新 Spectre.Console?

问题描述 投票:0回答:1

我正在使用 COM 连接为设备控制器编写代码。在我的代码中,我有 3 个线程,侦听器、编写器和状态询问线程,对于每个线程,我计划使用 Spectre.Console 输出其状态(工作或暂停)和一个计时器以用于测试目的

LiveDisplay

我不知道当每个线程的状态属性发生变化时如何更新控制台。更新控制台需要在每次每个线程的状态发生变化时调用

ctx.Refresh()
,但我没有找到一种方法来调用它而不是从
AnsiConsole.Start()
方法。

我使用一个单独的类来存储状态,我从线程向其传递值,实现

INotifyPropertyChanged
。我仍然不确定在单独的类中实现它是否是一个好方法,所以我计划重新审视它,也许将它与控制器类一起加入。

这是我用于存储状态的类:

internal class ControllerData : INotifyPropertyChanged
    {
        private string _writeThreadState = "";
        private string _readThreadState = "";
        private string _stateThreadState = "";
        private string _actionMessage = "";

        public String WriteThreadState
        {
            get => _writeThreadState;
            set
            {
                _writeThreadState = value;
                OnPropertyChanged(nameof(WriteThreadState));
            }
        }
        public String ReadThreadState
        {
            get => _readThreadState;
            set
            {
                _readThreadState = value;
                OnPropertyChanged(nameof(ReadThreadState));
            }
        }
        public String StateThreadState
        {
            get => _stateThreadState;
            set
            {
                _stateThreadState = value;
                OnPropertyChanged(nameof(StateThreadState));
            }
        }
        public String ActionMessage
        {
            get => _actionMessage;
            set
            {
                _actionMessage = value;
                OnPropertyChanged(nameof(ActionMessage));
            }
        }
        public StringBuilder Output { get; set; } = new StringBuilder();

        public event PropertyChangedEventHandler? PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

记录器类:

internal class Logger
    {
        private ControllerData data;

        public Logger(Controller cont)
        {
            data = cont.loggingData;
            data.PropertyChanged += ControllerDataPropertyChangedHandler;
        }

        private void ControllerDataPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
        {
            //refresh console
        }



        public void Start()
        {
            Table table = new Table()
                .Border(TableBorder.Rounded)
                .AddColumn("Thread")
                .AddColumn("State");

            table.AddRow("Listen Thread", data.ReadThreadState);
            table.AddRow("Write Thread", data.WriteThreadState);
            table.AddRow("Check state Thread", data.StateThreadState);


             AnsiConsole.Live(table)
                .Start(ctx =>
                {
                    ctx.Refresh();
                });

        }

    }

主要:

 static void Main(string[] args)
        {
            ComConnector connector = new ComConnector();

            try
            {
                Controller cont = new Controller(connector);
                Logger log = new Logger(cont);
                log.Start();
                cont.StartMessaging(20000);
                
                
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }

        }
    }
c# .net multithreading spectre.console
1个回答
0
投票

这可能需要您重新考虑您的设计,但我通常这样做:

using Spectre.Console;
using SpectreTest;

Console.OutputEncoding = System.Text.Encoding.Unicode;

var table = new Table().AddColumns("Key", "Value");

await AnsiConsole.Live(table).StartAsync(async ctx =>
{
    var sim = new CommunicationEmulator();
    var entries = new Dictionary<string, int>();

    await sim.SimulateAsync(new Progress<Update>(u =>
    {
        if (entries.TryGetValue(u.Key, out var rowIndex))
        {
            table.UpdateCell(rowIndex, 1, u.Value);
        }
        else
        {
            var columns = new List<Markup> { Markup.FromInterpolated($"{u.Key}"), Markup.FromInterpolated($"{u.Value}") };
            var index = table.Rows.Add(columns);
            entries[u.Key] = index;
        }

        ctx.Refresh();
    }));
});

public record Update(string Key, string Value);

不管怎样,这显示了一个表格,该表格将由我在此处称为

CommunicationEmulator
的报告进行实时更新。

您可能也可以使用

  • 频道
  • 反应式

要点是在

StartAsync
内部循环并发出更新,并保持从某种键到实际表的行索引的映射。

请注意,这考虑了用户输入。它会一直运行,直到模拟器不再有输入为止。

© www.soinside.com 2019 - 2024. All rights reserved.