Завершить один поток, начать другой. Или вариант как сделать верно

Рейтинг: 0Ответов: 1Опубликовано: 18.02.2023

Всем привет!

Выполняю команды в CMD, вывод приходит из StreamReader в textbox Так же присутсвует ProgressBar.

Мне надо дождаться выполнения как бы это странно не звучало потока, и начать новый. Иначе я не получаю последовательный вывод из CMD + ProgressBar отключается раньше времени тут: progressBar.Invoke(new MethodInvoker(() => { progressBar.Visible = false; }))

private void buttonGetSoft_Click(object sender, EventArgs e)
    {

        Info("Установка MyAsus");
        progressBar.Visible = true;
        buttonGetSoft.Enabled = false;
        string script1 = @"/C cd C:\Windows\System32 && winget install 9N7R5S6B0ZZH --accept-package-agreements";
        Task task = new Task(() => DoWork(script1, System.Windows.Forms.Button));
        task.Start();

        //
        // Как вот это разделить, что бы они последовательно выполнялись? Но не Асинхронно, иначе я не смогу получить построчный вывод из CMD, в textbox.
        //

        Info("Проверка Версии MS WinGet");
        buttonGetSoft.Enabled = false;
        progressBar.Visible = true;
        string script = @"/C winget -v";
        Task task1 = new Task(() => DoWork(script, sender as System.Windows.Forms.Button));
    }

Метод который выводит поток ( инфу из CMD ) в textbox:

 public void DoWork(string script, Control control)
    {
        Process cmd = new Process();
        cmd.StartInfo.RedirectStandardOutput = true;
        cmd.StartInfo.UseShellExecute = false;
        cmd.StartInfo.FileName = "cmd.exe";
        cmd.StartInfo.Verb = "runas";
        cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        cmd.StartInfo.Arguments = script;
        cmd.StartInfo.CreateNoWindow = true;
        cmd.Start();
        cmd.WaitForExit();

        if (!cmd.StartInfo.RedirectStandardOutput)
        {
            MessageBox.Show("Невозможная ошибка");
            return;
        }

        string eline;
        StreamReader sr = cmd.StandardOutput;

        while (!sr.EndOfStream)
        {
            eline = sr.ReadLine();
            textboxInfo.Invoke(new MethodInvoker(() => {
            textboxInfo.Text += eline + Environment.NewLine;
                textboxInfo.SelectionStart = textboxInfo.TextLength;
                Thread.Sleep(5);
                textboxInfo.ScrollToCaret();
            }));
        }

        control.Invoke(new MethodInvoker(() => { control.Enabled = true; }));
        progressBar.Invoke(new MethodInvoker(() => { progressBar.Visible = false; }));         
    }

Либо я не понимаю, как это объединить с backgroundWorker. Там я не могу получить построчный вывод на лету.

Направьте пожалуйста, или может простой пример кому не жалко, я хорошо понимаю именно на них.

Ответы

▲ 2Принят

Самое простое здесь - async/await

private async void buttonGetSoft_Click(object sender, EventArgs e)
{
    Button button = (Button)sender;
    button.Enabled = false;
    progressBar.Visible = true;
    IProgress<string> progress = new Progress<string>(s => 
    {
        textboxInfo.AppendText(s + Environment.NewLine);
        textboxInfo.ScrollToCaret();
    });
    try
    {
        Info("Установка MyAsus");
        string script = @"/C cd C:\Windows\System32 && winget install 9N7R5S6B0ZZH --accept-package-agreements";
        await Task.Run(() => DoWork(script, progress));

        Info("Проверка Версии MS WinGet");
        script = @"/C winget -v";
        await Task.Run(() => DoWork(script, progress));
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    progressBar.Visible = false;
    button.Enabled = true;
}

public void DoWork(string script, IProgress<string> progress)
{
    Process cmd = new Process();
    cmd.StartInfo.RedirectStandardOutput = true;
    cmd.StartInfo.UseShellExecute = false;
    cmd.StartInfo.FileName = "cmd.exe";
    cmd.StartInfo.Verb = "runas";
    cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    cmd.StartInfo.Arguments = script;
    cmd.StartInfo.CreateNoWindow = true;
    cmd.Start();
    cmd.WaitForExit();

    StreamReader sr = cmd.StandardOutput;
    while (!sr.EndOfStream)
    {
        progress.Report(sr.ReadLine());
    }       
}

Второй вариант с выводом в режиме реального времени

private async void buttonGetSoft_Click(object sender, EventArgs e)
{
    Button button = (Button)sender;
    button.Enabled = false;
    progressBar.Visible = true;
    try
    {
        Info("Установка MyAsus");
        string script = @"/C cd C:\Windows\System32 && winget install 9N7R5S6B0ZZH --accept-package-agreements";
        await Task.Run(() => DoWork(script));

        Info("Проверка Версии MS WinGet");
        script = @"/C winget -v";
        await Task.Run(() => DoWork(script));
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    progressBar.Visible = false;
    button.Enabled = true;
}

public void DoWork(string script)
{
    Process cmd = new Process();
    cmd.StartInfo.RedirectStandardOutput = true;
    cmd.StartInfo.RedirectStandardError = true;
    cmd.OutputDataReceived += Cmd_OutputDataReceived;
    cmd.ErrorDataReceived += Cmd_OutputDataReceived;
    cmd.StartInfo.UseShellExecute = false;
    cmd.StartInfo.FileName = "cmd.exe";
    cmd.StartInfo.Verb = "runas";
    cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    cmd.StartInfo.Arguments = script;
    cmd.StartInfo.CreateNoWindow = true;
    cmd.Start();
    cmd.BeginOutputReadLine();
    cmd.BeginErrorReadLine();
    cmd.WaitForExit();   
}

private void Cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    this.Invoke((Action)(() =>
    {
        textboxInfo.AppendText(e.Data + Environment.NewLine);
        textboxInfo.ScrollToCaret();
    }));
}