当我使进程正常工作时,当我尝试添加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;
}
它只运行整个过程,而我的栏没有显示。
在此过程中如何生成进度条?
答案 0 :(得分: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();
}