Los que tienen la posibilidad de utilizar Windows 7 habrán notado que trae varias novedades como la vista en miniatura de las aplicaciones minimizadas al pasar el mouse sobre ellas, que algunas de éstas, como el Windows Media Player, en esa vista poseen botones, y otras como el Internet Explorer utilizan el ícono de la barra de tareas como indicador de progreso (en el IE se utiliza para mostrar el progreso de las descargas). Todas estas características y algunas más que aquí no nombro (por ejemplo, hay una característica gracias a la cual, con un dispositivo de tal sólo u$s 30, se puede medir la luz ambiental y, si lo programamos, se puede cambiar el tema de pantalla dependiendo de la misma) son programables a través de las API del sistema operativo para brindarle a nuestras aplicaciones todas las posibilidades que posee. En este artículo hablaré de la posibilidad de mostrar el progreso de una operación como fondo del ícono de la misma en la barra de tareas.
Las aplicaciones que corren sobre Windows 7 pueden mostrar el progreso de una tarea que están ejecutando en el ícono de la barra de tareas, evitando de esta manera que el usuario tenga que abrir la ventana de la misma para verificar el estado del proceso. A continuación detallo los posibles estados que se pueden mostrar:
Aplicación sin barra de progreso | |
Aplicación con estado normal y 50% de progreso | |
Aplicación con estado pausado y 50% de progreso | |
Aplicación con error y 50% de progreso | |
Aplicación con estado indeterminado |
Para modificar el estado y el valor de progreso de nuestras aplicaciones podemos utilizar la interfaz ITaskbarList3 como se muestra a continuación
ITaskbarList3* pTL; //creado anteriormente HRESULT hr = pTL->SetProgressState(hwnd, TBPF_NORMAL); //hwnd es el puntero de la ventana pTL->SetProgressValue(50, 100); //Establecemos un 50% de progreso
Para los que desarrollamos en .NET este código en C no nos sirve de mucho, entonces podemos referenciar las clases e interfaces COM o, mejor aún, podemos utilizar las librerías “Windows® API Code Pack for Microsoft® .NET Framework” que ya tienen resuelto este tema. Estas librerías, junto con su código fuente y ejemplos, las podemos bajar de la siguiente dirección: http://code.msdn.microsoft.com/WindowsAPICodePack. Para cambiar el estado y progreso de nuestra aplicación debemos utilizar los métodos SetProgressState y SetProgressValue de la clase Microsoft.WindowsAPICodePack.Taskbar.TaskbarManager respectivamente.
A continuación muestro un ejemplo en WPF de un proyecto en el cual se cambia el progreso de la aplicación modificando el valor de un control Slider, y el estado de la misma a través de un ComboBox. El XAML de éste es el siguiente:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="TaskBarProgress.Window1" Title="Ejemplo de barra de progreso en la barra de tareas" Height="170" Width="400" WindowStartupLocation="CenterScreen" WindowStyle="SingleBorderWindow" MaxHeight="170" MinHeight="170" MinWidth="320" Icon="Scientia.ico"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" MinWidth="178" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition Height="Auto" MinHeight="36" /> </Grid.RowDefinitions> <TextBlock HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="15" FontWeight="Bold" Margin="5" Text="Estado de la aplicación:" /> <ComboBox x:Name="ComboBox1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Stretch" Margin="5" SelectionChanged="ComboBox_SelectionChanged"> <ComboBoxItem>Normal</ComboBoxItem> <ComboBoxItem>Pausado</ComboBoxItem> <ComboBoxItem>Con error</ComboBoxItem> <ComboBoxItem>Indeterminado</ComboBoxItem> <ComboBoxItem IsSelected="True">Sin progreso</ComboBoxItem> </ComboBox> <TextBlock HorizontalAlignment="Right" FontSize="15" FontWeight="Bold" Grid.Row="1" VerticalAlignment="Center" Text="Porcentaje de progreso:" Margin="5" /> <Slider x:Name="Slider1" Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Margin="5" SmallChange="1" Maximum="100" LargeChange="10" TickPlacement="Both" TickFrequency="5" ValueChanged="Slider_ValueChanged" /> <TextBlock Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="10"><Run Text="Desarrollado por "/><Hyperlink NavigateUri="http://www.scientia.com.ar" RequestNavigate="Hyperlink_RequestNavigate"><Run Text="Scientia® Soluciones Informáticas"/></Hyperlink></TextBlock> </Grid> </Window>
Y el código C# es el que muestro a continuación:
using System; using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using Microsoft.WindowsAPICodePack.Taskbar; namespace TaskBarProgress { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { private TaskbarManager windowsTaskbar = TaskbarManager.Instance; public Window1() { if ((Environment.OSVersion.Version.Major < 6) || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 1)) { MessageBox.Show("Esta aplicación de ejemplo requiere Windows® 7 o superior para correr", "Scientia® Soluciones Informáticas", MessageBoxButton.OK, MessageBoxImage.Error); Close(); } else InitializeComponent(); } private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) { Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); e.Handled = true; } private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (ComboBox1.SelectedIndex != 4) windowsTaskbar.SetProgressValue(Convert.ToInt32(e.NewValue), 100, this); } private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { switch ((sender as ComboBox).SelectedIndex) { case 0: //Normal windowsTaskbar.SetProgressState(TaskbarProgressBarState.Normal, this); break; case 1: //Pausado windowsTaskbar.SetProgressState(TaskbarProgressBarState.Paused, this); break; case 2: //Con error windowsTaskbar.SetProgressState(TaskbarProgressBarState.Error, this); break; case 3: //Indeterminado windowsTaskbar.SetProgressState(TaskbarProgressBarState.Indeterminate, this); return; case 4: //Sin progreso windowsTaskbar.SetProgressState(TaskbarProgressBarState.NoProgress, this); return; } windowsTaskbar.SetProgressValue(Convert.ToInt32(Slider1.Value), 100, this); } } }
Obviamente todo el código mostrado funciona solamente sobre Windows® 7 por cual, si queremos hacer una aplicación que también sea compatible con versiones anteriores del sistema operativo, nos conviene verificar la versión de éste antes de utilizar estas características. Esto se puede hacer de la siguiente forma:
if ((Environment.OSVersion.Version.Major > 6) || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1)) { //Es Windows 7 o superior } else { //Es un sistema operativo anterior a Windows® 7 }