在Front-end Application, 當有request 須要進行較長時間的處理, (例如web API call, 檔案IO等), 通常除了disable UI controls 外, 為了令user 知道處理狀況, 便須要利用Progress bar 表達運作進度.
在WPF中, 與HTML5 一樣, 都可以利用<ProgressBar> 實現. 然而, 在TaskBar 中的圖示, 則須要再作處理. 在示範中, 用了code-behide 作Proof-of-Concept, 相信利用MVVM 都能夠順利使用.
MainWindow.xaml
<Window x:Class="Poc.ProgressBar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Poc.ProgressBar"
mc:Ignorable="d"
Title="MainWindow" Height="130" Width="500">
<Window.Resources>
<Style TargetType="ProgressBar">
<Setter Property="Height" Value="45" />
<Setter Property="Margin" Value="5" />
<Style.Triggers>
<Trigger Property="IsIndeterminate" Value="False">
<Setter Property="Background" Value="#80B5FFA9" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="Button">
<Setter Property="Width" Value="100" />
<Setter Property="Margin" Value="5" />
</Style>
</Window.Resources>
<Window.TaskbarItemInfo>
<TaskbarItemInfo ProgressState="Normal" />
</Window.TaskbarItemInfo>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<ProgressBar Name="progTest" Grid.Row="0"></ProgressBar>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<Button Name="btnPause" Click="btnPause_Click">Pause</Button>
<Button Name="btnError" Click="btnError_Click">Error</Button>
</StackPanel>
</Grid>
</Window>
在Windows 7 後, 透過TaskbarItemInfo, 可以控制Application 狀況的表示. 主要為Normal , Indeterminate, Error.
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private const double TASKBAR_PROGRESS_VALUE_MAX = 1.0;
private const int PROGRESS_BAR_PERCENTAGE_MIN = 0;
private const int PROGRESS_BAR_PERCENTAGE_MAX = 100;
private const int THREAD_DEFAULT_SLEEP_MILLIAN_SECOND = 100;
private BackgroundWorker _testWorker = new BackgroundWorker();
private bool _isPause = false;
private bool _isCancel = false;
public MainWindow()
{
InitializeComponent();
_testWorker.WorkerReportsProgress = true;
_testWorker.WorkerSupportsCancellation = true;
_testWorker.DoWork += _testWorker_DoWork;
_testWorker.ProgressChanged += _testWorker_ProgressChanged;
_testWorker.RunWorkerCompleted += _testWorker_RunWorkerCompleted;
_testWorker.RunWorkerAsync();
}
private void _testWorker_DoWork(object sender, DoWorkEventArgs e)
{
int i = 0;
while ((i <= PROGRESS_BAR_PERCENTAGE_MAX) && (!_isPause) && (!_isCancel))
{
i++;
System.Threading.Thread.Sleep(THREAD_DEFAULT_SLEEP_MILLIAN_SECOND);
_testWorker.ReportProgress(i);
}
}
private void _testWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progTest.Value = e.ProgressPercentage;
TaskbarItemInfo.ProgressValue = e.ProgressPercentage / PROGRESS_BAR_PERCENTAGE_MAX;
}
private void _testWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (_isCancel)
{
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Error;
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
MessageBox.Show("Application Cancel.");
Application.Current.Shutdown();
}
else if (_isPause)
{
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Paused;
MessageBox.Show("Application Pause.");
}
else
{
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate;
if (MessageBox.Show("Load completed, close application now?", "Exit Application", MessageBoxButton.YesNo)
.Equals(MessageBoxResult.Yes))
{
Application.Current.Shutdown();
}
}
}
private void btnPause_Click(object sender, RoutedEventArgs e)
{
if (_isPause)
{
_isPause = false;
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
}
else
{
_isPause = true;
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Paused;
}
}
private void btnError_Click(object sender, RoutedEventArgs e)
{
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Error;
_isCancel = true;
_testWorker.CancelAsync();
}
}
在這裡, 利用BackgroundWorker 作示範, 控制ProgressBar 的運作. ProgressBar 須要留意的如下:
- ProgressBar value 須要以1-100 代表其百分比; 而TaskBarItemInfo 則須要除以100;
- TaskBar 狀態 以 enum TaskbarItemProgrssState表示;
Reference
Programming the Task Bar in Windows 7 with WPF 4, Part Four – Progress Bar Icon, MSDN
Leave a Reply