掘金 后端 ( ) • 2024-05-08 10:52

前言

在日常开发过程中,如果遇到需要一段时间才能完成的任务,通常需要给用户一个进度条提示。今天给大家介绍的是WPF/C#中ProgressBar的基本使用。

ProgressBar的介绍

在WPF(Windows Presentation Foundation)中,ProgressBar是一个用户界面元素,用于显示一个操作的进度。

ProgressBar有两种模式:确定模式和不确定模式。

  1. 确定模式:在确定模式下,ProgressBar显示一个操作的完成百分比。你可以通过设置ProgressBarMinimumMaximumValue属性来控制进度条的显示。例如,如果你设置Minimum为0,Maximum为100,然后将Value设置为50,那么ProgressBar将显示为一半填充(表示操作完成了50%)。
  2. 不确定模式:在不确定模式下,ProgressBar显示一个持续的动画,表示一个操作正在进行,但是没有指定完成百分比。你可以通过设置ProgressBarIsIndeterminate属性为true来启用不确定模式。

不确定模式的使用

xaml:

<StackPanel>
    <Button Content="执行耗时任务" Margin="20"
            Click="Button_Click"></Button>
    <ProgressBar Margin="50" x:Name="progressBar1" Width="300" Height="20" 
           IsIndeterminate="True" Visibility="Hidden" />
</StackPanel>

cs:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    progressBar1.Visibility = Visibility.Visible;
    await Task.Delay(5000);
    progressBar1.Visibility = Visibility.Hidden;
}

假设在执行一个耗时任务,可以先将ProgressBarIsIndeterminate属性设置为True,表示使用不确定模式,也就是进度条一直在动,然后设置Visibility属性为Hidden,使ProgressBar刚开始不可见。在执行任务前,让它可见,再任务完成后,再让它不可见。

实现的效果如下图所示:

不确定模式的使用效果

确定模式的使用

xaml:

 <StackPanel>
     <Button Content="执行耗时任务" Margin="20"
             Click="Button_Click"></Button>
     <ProgressBar Margin="50" x:Name="progressBar1" Width="300" Height="20" 
            Minimum="0" Maximum="100" Visibility="Hidden" />
 </StackPanel>

cs:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    progressBar1.Visibility = Visibility.Visible;
    for (int i = 0; i <= 100; i++)
    {
        int progress = i;
        await Task.Delay(50);  // 等待50毫秒
        Dispatcher.Invoke(() => progressBar1.Value = progress);  // 更新ProgressBar的值
    }
    progressBar1.Visibility = Visibility.Hidden;
}

使用

Dispatcher.Invoke(() => progressBar1.Value = progress);

是因为在WPF中,只有创建控件的线程(通常是主UI线程)才能访问该控件。这被称为线程关联或线程亲和性。如果你尝试从另一个线程访问控件,例如从异步任务中更新控件的属性,你将会收到一个异常。

Dispatcher.Invoke方法允许你在创建控件的线程上执行特定的操作。Dispatcher.Invoke(() => MyProgressBar.Value = progress);这行代码将更新ProgressBarValue属性的操作发送到主UI线程上执行。这样,即使这个操作是从异步任务中调用的,也不会收到线程亲和性的异常。

总的来说,每当你需要从非UI线程更新UI控件时,你都需要使用Dispatcher.Invoke或类似的方法来确保操作在正确的线程上执行。

实现效果如下所示:

确定模式的使用效果

HandyControl中的ProgressBar的使用

HandyControl是一个基于WPF(Windows Presentation Foundation)的开源UI库,它提供了一套丰富、灵活且实用的控件集,可以帮助开发者更容易地创建美观且功能强大的桌面应用程序。

HandyControl中ProgressBar的使用效果如下所示:

使用效果

跟自带的用法差不多,现在从三个类别中分别选一种做示例。

不确定模式的用法

对应图中的第二种类别。

xaml:

<StackPanel>
    <Button Content="执行耗时任务" Margin="20"
            Click="Button_Click"></Button>
    <hc:CircleProgressBar x:Name="progressBar1" IsIndeterminate="True" 
                          Margin="20" Width="100" Height="100"
                          ArcThickness="6"  Visibility="Hidden"
                          Style="{StaticResource ProgressBarInfoCircle}"/>
</StackPanel>

cs:

 private async void Button_Click(object sender, RoutedEventArgs e)
 {      
     progressBar1.Visibility = Visibility.Visible;
     await Task.Delay(5000);         
     progressBar1.Visibility = Visibility.Hidden;
 }

实现效果如下所示:

效果

确定模式的用法

图中第一种。

xaml:

<StackPanel>
    <Button Content="执行耗时任务" Margin="20"
            Click="Button_Click"></Button>    
    <hc:CircleProgressBar x:Name="progressBar1" Visibility="Hidden"
                          Margin="20" ShowText="True" Width="80" Height="80" ArcThickness="5" 
                          Style="{StaticResource ProgressBarSuccessCircle}"/>
</StackPanel>

cs:

 private async void Button_Click(object sender, RoutedEventArgs e)
 {      
     progressBar1.Visibility = Visibility.Visible;
     for (int i = 0; i <= 100; i++)
     {
         int progress = i;
         await Task.Delay(50);  // 等待50毫秒
         Dispatcher.Invoke(() => progressBar1.Value = progress);  // 更新ProgressBar的值               
     }
     progressBar1.Visibility = Visibility.Hidden;
 }

实现效果:

效果

图中第三种。

xaml:

<StackPanel>
    <Button Content="执行耗时任务" Margin="20"
            Click="Button_Click"></Button>   
    <hc:WaveProgressBar x:Name="progressBar1" />
</StackPanel>

cs:

private async void Button_Click(object sender, RoutedEventArgs e)
{      
    progressBar1.Visibility = Visibility.Visible;
    for (int i = 0; i <= 100; i++)
    {
        int progress = i;
        await Task.Delay(50);  // 等待50毫秒
        Dispatcher.Invoke(() => progressBar1.Value = progress);  // 更新ProgressBar的值               
    }
    progressBar1.Visibility = Visibility.Hidden;
}

实现效果:

效果

总结

本文介绍了WPF/C#中ProgressBar控件的基本使用,该控件有两种使用方式,分别为确实模式与不确定模式,确实模式就是知道进度是如何变化的,不确定模式就是不确定进度的变化情况,进度条一直在动,由于自带的ProgressBar只有条形的,可能无法满足日常的开发需求,因此跟大家介绍了HandyControl中ProgressBar的用法,在HandyControl的进度条有其他样式。希望对正在学习WPF的同学有所帮助。