在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