【问题标题】:WPF Application Indefinite progress bar doesn't show but processes are running on backgroundWPF 应用程序无限进度条不显示,但进程正在后台运行
【发布时间】:2018-12-31 02:01:20
【问题描述】:

当我让进程开始工作时,当我尝试添加 ProgressBar 以向用户提供进程没有崩溃的线索时,我可能遇到了线程问题。既然这已经足够了,那么 Indefinite ProgressBar 对我来说就很好了。

 <ProgressBar x:Name="ProcessProgress" Minimum="0" Maximum="100" Visibility="Hidden" IsIndeterminate="False" Width="305" Height="20" Margin="240,214,248,10"></ProgressBar>

我试图启动一个确定长度的进度条,在单击“开始”按钮之前它是不可见的:

private void Start_Click(object sender, RoutedEventArgs e)
{
    ...
    //process starts here
    var fP = new FileProcessor();
    ProcessProgress.IsIndeterminate = true;
    ProcessProgress.Visibility = Visibility.Visible;

    ...
    //finally show the progressbar as full when done
    ProcessProgress.IsIndeterminate = false;
    ProcessProgress.Value = ProcessProgress.Maximum;

}

它只是运行整个过程,我的栏没有出现。

如何在此过程中生成进度条?

【问题讨论】:

  • 异步等待是要走的路。无论如何,您都不应该对背后的代码进行实际操作。应该通过 ViewModel + 命令模式来完成。我知道它有很多东西要学,但如果你要做,最好做对:)
  • @Steve 是的,你完全正确,我很欣赏这个姿态。我可以要求一个适当的提示(可能是链接或参考书目,一系列视频)?我想很快参与进来,因为在下个月初我需要将它连接到一个 SQL 服务器,而我的团队合作伙伴实际上都没有编写代码(如果你知道我的意思的话)。
  • 关键字:“MVVM”、“WPF ICommand”、“async await”、“c# Task”。谷歌这些教程并很好地了解它们是什么以及如何正确使用它们然后你就可以开始了。可能需要 2 周以上才能完成所有工作。 Sql 需要几个月的时间才能掌握,所以请记住这一点。
  • 我不能说这是否适用于您的特定情况,但请参阅我的 answer 我在其中谈论这个特定主题。
  • @scharette 感谢您的评论。我很快就会达到顶峰,希望它能带来红利,因为我们真的真的真的没有时间了。 :(

标签: c# wpf user-interface async-await


【解决方案1】:

问题是您的所有代码都在 UI 线程中运行。在整个过程完成之前,UI 没有机会自我更新。

您可以使用Task.Run() 在后台运行繁重的作业,而不会阻塞 UI。您可以使用 await 关键字来等待该任务完成而不阻塞 UI。任务完成后,您将返回 UI 线程,您可以在其中再次修改 UI。

对此事件处理程序的快速而肮脏的修复是:

private async void Start_Click(object sender, RoutedEventArgs e)
{
    ProcessProgress.IsIndeterminate = true;
    ProcessProgress.Visibility = Visibility.Visible;
      ...
    await Task.Run(()=>
    {
        //process starts here
        var fP = new FileProcessor();

        ...
    });

    //We are back in the UI thread, we can modify the UI
    ProcessProgress.IsIndeterminate = false;
    ProcessProgress.Value = ProcessProgress.Maximum;
}

无需使用Invoke 回到UI 线程,这是await 本身的工作。

关于async void 的注释。它适用于事件处理程序或类似方法。您不能等待async void 方法,这意味着如果出现问题,您甚至无法获得任何异常。不返回任何内容的异步方法应具有async Task 签名。

如果您想报告进度,您可以使用IProgress 接口和Progress 类,如here 所述。 Progress 类将在它创建的线程上调用回调或引发事件。有效载荷可以是任何类,而不仅仅是百分比

最好将报告代码移动到单独的方法中,以保持按钮处理程序干净。代码如下所示:

//The progress class
class FileProgress
{
    public string FileName{get;set;}
    public int Progress{get;set;}
    public string Message{get;set;}

    public FileProgress(string fileName,int progress,string message)
    {
        FileName=filename;
        Progress=progress;
        Message=message;
    }
}

//In the form itself
private void ReportStart()
{
    ProcessProgress.IsIndeterminate = true;
    ProcessProgress.Visibility = Visibility.Visible;
}

private void ReportEnd()
{
    ProcessProgress.IsIndeterminate = false;
    ProcessProgress.Value = ProcessProgress.Maximum;
}

private void ReportProgress(FileProgress progress)
{
    ProcessProgress.Value =progress.Progress;        
    PanelStatus.Text = $"Working on {progress.FileName} : {progress.Message}";
}

事件处理程序现在看起来像这样:

private async void Start_Click(object sender, RoutedEventArgs e)
{
    ReportStart();

    IProgress<FileProgress> progress=new Progress<FileProgress>(ReportProgress);
      ...
    await Task.Run(()=>
    {
        //process starts here
        var fP = new FileProcessor();

        foreach(var file in someFiles)
        {
              progress.Report(new FileProgress(file,0,"Starting");
              //Do some processing
              progress.Report(new FileProgress(file,100,"Finished");
        }
        ...
    });

    //We are back in the UI thread, we can modify the UI
    ReportEnd();
}

【讨论】:

  • 我相信这是我应该说声谢谢的时刻。实施这种方法消除了我所有的错误,现在我只有一件事要解决,那就是要问的另一个问题。先生,这个答案很重要。
猜你喜欢
  • 2013-09-13
  • 2020-06-17
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多