使用 cmd 进程发送的进度百分比更新进度条

Updating progress bar using progress percentage sent by a cmd process

提问人:mehrshad 提问时间:10/20/2023 最后编辑:mehrshad 更新时间:10/31/2023 访问量:51

问:

我是 C# Windows 窗体的新手。我想使用从 cmd 进程接收的标准输出数据更新程序中的进度条。

起初它不允许我更新栏并给了我错误。因此,我去异步启动了该过程,并将一个处理程序挂接到并用于逐行异步读取数据,并将一个传递给处理程序,该处理程序将调用另一个事件来更新进度条。can not access the bar from multiple threadsOutputDataReceivedprocess.BeginOutputReadLine()IProgress<ProgressReportDataModel>

唯一的问题是进度百分比数据都集中在一行中,当调用事件时,进程已经完成进度条跳转到 100%。如何在此处更新进度条?OutputDataReceived

下面的代码是调用的方法:Task.Run()

private int FlasherRun(string args, IProgress<ProgressReportDataModel> progress)
{
    ProgressReportDataModel report = new(); // for resetting bar when finished

    Process process = new Process();
    ProcessStartInfo startInfo = new ProcessStartInfo();

    startInfo.FileName = programmerFileName;
    startInfo.Arguments = args;
    startInfo.CreateNoWindow = true;
    startInfo.RedirectStandardOutput = true;

    process.StartInfo = startInfo;

    process.OutputDataReceived +=
        (Object _sender, DataReceivedEventArgs _args)
            => FlasherOutputHandler(_sender, _args, progress);

    process.Start();

    process.BeginOutputReadLine();

    process.WaitForExit();

    // Reset progress bar
    report.progressPercentageComplete = 0;
    progress.Report(report);

    return process.ExitCode;
}

下面的函数是接收数据的处理程序:

private void FlasherOutputHandler(object sendingProcess, DataReceivedEventArgs outLine,
    IProgress<ProgressReportDataModel> progress)
{
    ProgressReportDataModel report = new ProgressReportDataModel();

    // extract percentage value from outLine.Data and then
    
    report.progressPercentageComplete = percentageValue;
    report.progressMessages = someMessage;
    progress.Report(report);
}

在调用第一个函数 async 之前,将挂接到下面的事件处理程序:progress.ProgressChanged

private void ReportProgressEvent(object? sender, ProgressReportDataModel e)
{
    progressBar.Value = e.progressPercentageComplete;
    messagesTextBox.Text += e.progressMessages;
}

下面是实例化和调用 FlasherRun 方法异步的方法。Progress<>

private async void btn_Click(object sender, EventArgs e)
{
    try
    {
        Progress<ProgressReportDataModel> progress = new Progress<ProgressReportDataModel>();
        progress.ProgressChanged += ReportProgressEvent;

        string flasherCMD = "some command";
        int exitCode = 0;

        exitCode = await Task.Run(() => FlasherRun(flasherCMD, progress));
        if (exitCode != 0)
        {
            MessageBox.Show("Error", "Error",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }
    }
    catch (Exception exception)
    {
        // exceptions are handled here
    }
}

我尝试在 while() 循环中使用方法一次一个字符读取来自标准输出的数据,并在传入数据中有新的可用百分比时调用进度更新,但这似乎没有在读取过程中调用进度更新程序事件,并且在阅读器完成并退出 while() 循环后,它以 100% 调用更新程序 20 次value,这是通过 streamreader 传入的最后一个值。process.StandardOutput.Read()

C# 异步 事件处理 进度条 iProgress

评论

0赞 Theodor Zoulias 10/22/2023
您能否编辑问题并包含实例化的方法并调用?我的猜测是,这是问题的根源。IProgress<ProgressReportDataModel>FlasherRunprocess.WaitForExit();
0赞 mehrshad 10/29/2023
@TheodorZoulias我已经完成了你要求的编辑。你怎么看?
0赞 Theodor Zoulias 10/29/2023
我的猜测是错误的。在 上运行,而不是在 UI 线程上运行。所以我不知道是什么导致了你的问题。FlasherRunThreadPool

答: 暂无答案