Я создаю оболочку для пакетной программы и не могу найти способ обновить вывод в реальном времени

#c# #wrapper

#c# #оболочка

Вопрос:

Я запускаю сервер, который представляет собой файл jar, который выполняется с помощью пакета. Я попытался создать для этого оболочку, но я не могу найти способ заставить выходные данные пакетного файла обновляться в режиме реального времени в текстовом поле.

Код, который я использую до сих пор, выглядит следующим образом:

 public partial class Form1 : Form
{

    string output = "Server has not been started yet...";

    public void button1_Click(object sender, EventArgs e)
    {
        Thread t = new Thread(batch); // Kick off a new thread
        t.Start(); // Running batch()

        Thread l = new Thread(loop);
        l.Start(); //Running loop
    }

    // This will run the batch file in the background
    public void batch()
    {
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.FileName = "cmd.exe";
        p.StartInfo.Arguments = "/c @echo off";
        p.StartInfo.Arguments = "/c java -Xms512M -Xmx1G -XX:MaxPermSize=128M -XX: UseConcMarkSweepGC -jar spigot.jar";
        p.Start();
        // reading to the end of its redirected stream.
        output = p.StandardOutput.ReadToEnd();

        // Can't do this because it only happens when the program
        // is exited and won't work cross-thread
        //textBox1.Text  = output;
    }

    // Can't use this either because it will repeat messages
    // and it's still cross-thread
    //public void loop()
    //{
        //bool update = true;

        //while (update == true)
        //{
            //textBox1.Text  = output;
        //}
    //}
  

Если вы не читали код, в основном моя главная проблема в том, что я не могу обновить перекрестный поток текстового поля, и я не могу использовать циклы, потому что они будут повторять сообщения, поэтому я не знаю, что делать.

Я новичок в c # forms и не могу найти никаких результатов о том, как создать пакетную оболочку.

Ответ №1:

Вызов textBox1.Invoke может быть ключевым моментом для обновления элемента управления GUI в вашей ситуации:

 public partial class Form1 : Form
    {
        private object _sync;
        private ConcurrentQueue<string> _outputs;
        private bool _running;
        private delegate void OutputHandler(string line);
        private OutputHandler _append;

        public Form1()
        {
            InitializeComponent();
            _sync = new Object();
            _outputs = new ConcurrentQueue<string>();
            _append = new OutputHandler(line => {
                textBox1.AppendText(line   "rn");
            });
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var p = new Process();
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.OutputDataReceived  = p_OutputDataReceived;
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = "/c @echo off";
            p.StartInfo.Arguments = "/c java -Xms512M -Xmx1G -XX:MaxPermSize=128M -XX: UseConcMarkSweepGC -jar spigot.jar";
            p.Start();
            p.BeginOutputReadLine();
            lock(_sync)
            {
                _running = true;
            }
            p.Exited  = p_Exited;
            Task.Run(() => UpdateOutput());
        }

        void p_Exited(object sender, EventArgs e)
        {
            lock(_sync)
            {
                _running = false;
            }
        }

        void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if(e.Data != null)
            {
                _outputs.Enqueue(e.Data);
            }
        }

        private async Task UpdateOutput()
        {
            await Task.Run(() =>
            {
                var running = _running;
                while (running)
                {
                    var line = default(string);
                    if (_outputs.TryDequeue(out line))
                    {
                        try
                        {
                            textBox1.Invoke(_append, line);
                        }
                        catch
                        {

                        }
                    }
                    lock (_sync)
                    {
                        running = _running;
                    }
                }
            });
        }
    }
  

Комментарии:

1. Итак, я попробовал использовать этот код, и он работает просто отлично, но не выдает никаких результатов при выходе из командной строки. Поскольку я довольно новичок, я не знаю, действительно ли вы создали код, который устанавливает выходные данные в текстовое поле, и если вы этого не сделали, я не знаю, куда мне его добавить.

2. @CadeMartinez, для вашей информации, вот одна вещь, о которой я забыл упомянуть textBox1 : this.textBox1.Multiline = true;