Click here to Skip to main content
15,867,704 members
Articles / Desktop Programming / WPF

WPF: Integrating our application with the Windows 7 Taskbar (I)

Rate me:
Please Sign up or sign in to vote.
4.50/5 (8 votes)
24 Jul 2010CPOL6 min read 43.1K   1.1K   24   3
The taskbar of Windows 7 is one of the major changes in the Operating System, and brings many advantages.

Introduction

In the last article, we talked about how important it is to exploit the features offered by the SO on which our application is running, and we saw how to integrate our application with the Windows 7 power system to make it " energy friendly". This time, we will talk about the taskbar of Windows 7; it is one of the major changes in the Operating System, and brings many advantages to facilitate quick and intuitive communication between our application and our users:

  • IconOverlay: This property of the toolbar allows us to place from our code a small 16x16 icon on the icon of our application, in the lower right corner, so we can warn our users of updates on the status of the application without showing them on the screen.
  • ProgressBar: Very useful indeed, allows us to place a progress bar under the icon of our application, with multiple states, and be able to communicate to our users the state and progress of a task while using other applications, getting maximizing productivity.
  • Jumplist: The Jumplist has quick links to parts of our application that appears when you right click on the icon in the taskbar; we can make our app go directly to a particular window without even starting yet.
  • Thumbnail toolbars: When you mouse over the icons of active applications, Windows 7 offers a preview of the window of that application; with Thumbnail Toolbars, you can add buttons to that view that execute in the application.

In this article we will focus on the first two: IconOverlay and ProgressBar, leaving the rest for another article.

.NET 3.5 vs. .NET 4

To access all these features, .NET 3.5 only had one way: interoperability with unmanaged Win32 APIs (like the article on power management); however, .NET 4 incorporates the functionality of the Windows 7 task bar in the framework itself so that "use and enjoyment" of these features is far easier. The code in this article is only useful for .NET 4.

Let's Begin

First and as usual, a picture is worth a thousand words; this time, we have two:

Tab001_small.PNGtab002_small.PNG

As you can see, I've put in the original plan with the icons .... and yes, I know, my engaging in the design is as harmful as weapons of mass destruction .... but that's why I am a programmer:)

Let's start. You must first create a new WPF Application project (File> New> Project); once established, we will design the main screen in the file MainWindow.xaml.

The styles that I used in this application are available in the download file Application.xaml; if you have questions about how to use / create styles, take a look at my two articles on this topic: here and here.

Well, to start working with the taskbar, we add an object to our XAML of type TaskbarItemInfo:

XML
<Window.TaskbarItemInfo>
    <TaskbarItemInfo/>
</Window.TaskbarItemInfo>

With this, we will have access to many properties of the Windows 7 taskbar easily and quickly.

IconOverlay

Tab001.PNG

We will now start working with IconOverlay. The first thing to do is add as a resource in our project the image files we want to use (PNG or ICO for transparencies).

Once this is done, we must create a DrawingImage resource on our window, for each image; in my case, there are five:

XML
<Window.Resources>
    <DrawingImage x:Key="IconRed">
        <DrawingImage.Drawing>
            <ImageDrawing Rect="0,0,16,16" 
              ImageSource="/WPF%20Icon%20Overlay%20And%20ProgressBar;
                           component/images/FireToy.ico" />
        </DrawingImage.Drawing>
    </DrawingImage>
    <DrawingImage x:Key="IconGreen">
        <DrawingImage.Drawing>
            <ImageDrawing Rect="0,0,16,16" 
               ImageSource="/WPF%20Icon%20Overlay%20And%20ProgressBar;
                            component/images/GreenToy.ico" />
        </DrawingImage.Drawing>
    </DrawingImage>
    <DrawingImage x:Key="IconBlue">
        <DrawingImage.Drawing>
            <ImageDrawing Rect="0,0,16,16" 
     ImageSource="/WPF%20Icon%20Overlay%20And%20ProgressBar;
                  component/images/BlueToy.ico" />
        </DrawingImage.Drawing>
    </DrawingImage>
    <DrawingImage x:Key="IconPink">
        <DrawingImage.Drawing>
            <ImageDrawing Rect="0,0,16,16" 
     ImageSource="/WPF%20Icon%20Overlay%20And%20ProgressBar;
                  component/images/PinkToy.ico" />
        </DrawingImage.Drawing>
    </DrawingImage>
    <DrawingImage x:Key="IconBlack">
        <DrawingImage.Drawing>
            <ImageDrawing Rect="0,0,16,16" 
     ImageSource="/WPF%20Icon%20Overlay%20And%20ProgressBar;
                  component/images/NinjaToy.ico" />
        </DrawingImage.Drawing>
    </DrawingImage>
</Window.Resources>

Once done, we create the TabItem with buttons and others:

XML
<TabItem Header="Taskbar IconOverlay" Name="TabItem1">
    <Grid>
        <Grid.Background>
            <ImageBrush ImageSource="pack://application:,,,/WPF Icon Overlay And ProgressBar;
         component/images/overlay.png" Stretch="Uniform" Opacity=".2" />
        </Grid.Background>
        <Grid.RowDefinitions>
            <RowDefinition Height=".33*"></RowDefinition>
            <RowDefinition Height=".33*"></RowDefinition>
            <RowDefinition Height=".33*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width=".2*"></ColumnDefinition>
            <ColumnDefinition Width=".2*"></ColumnDefinition>
            <ColumnDefinition Width=".2*"></ColumnDefinition>
            <ColumnDefinition Width=".2*"></ColumnDefinition>
            <ColumnDefinition Width=".2*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
                    
        <Label Grid.ColumnSpan="5" Grid.Row="0" VerticalContentAlignment="Center" 
               HorizontalContentAlignment="Center" FontSize="24" Foreground="White"
               Content="Seleccione una imagen para superponer">
        </Label>
                    
        <Button Grid.Column="0" Grid.Row="1" Name="btnIconRed" 
                           Width="64" Height="64" Padding="0">
            <Button.Content>
                <Image Source="{StaticResource IconRed}" Width="56" 
                     Height="56" Stretch="Uniform" Margin="0"></Image>
             </Button.Content>
        </Button>
        <Button Grid.Column="1" Grid.Row="1" Name="btnIconGreen" 
                     Width="64" Height="64" Padding="0">
            <Button.Content>
                <Image Source="{StaticResource IconGreen}" 
                        Width="56" Height="56" Stretch="Uniform" 
                        Margin="0"></Image>
            </Button.Content>
        </Button>
        <Button Grid.Column="2" Grid.Row="1" Name="btnIconBlue" 
                    Width="64" Height="64" Padding="0">
            <Button.Content>
                <Image Source="{StaticResource IconBlue}" 
                      Width="56" Height="56" Stretch="Uniform" 
                      Margin="0"></Image>
            </Button.Content>
        </Button>
        <Button Grid.Column="3" Grid.Row="1" Name="btnIconPink" 
                       Width="64" Height="64" Padding="0">
            <Button.Content>
                <Image Source="{StaticResource IconPink}" 
                      Width="56" Height="56" Stretch="Uniform" 
                      Margin="0"></Image>
            </Button.Content>
        </Button>
        <Button Grid.Column="4" Grid.Row="1" Name="btnIconBlack" 
                       Width="64" Height="64" Padding="0">
            <Button.Content>
                <Image Source="{StaticResource IconBlack}" 
                        Width="56" Height="56" Stretch="Uniform" 
                        Margin="0"></Image>
            </Button.Content>
        </Button>                    
                    
        <Button Grid.ColumnSpan="5" Grid.Row="2" Name="btnIconReset" 
               Width="125" Height="30" Content="Reset Overlay"></Button>
    </Grid>
</TabItem>

We're done with all the XAML necessary for the IconOverlay. Now let us write the code. The first thing is, in our Window Loaded event, set the status of IconOverlay to none:

VB
Private Sub MainWindow_Loaded(ByVal sender As Object, _
         ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    Me.TaskbarItemInfo.Overlay = Nothing
End Sub

You can see that accessing the properties of our application icon in the taskbar is very simple because of the TaskbarItemInfo object we created in XAML. In this case, assigning Nothing indicates we have no icon associated.

Now, in the Click event of each button, we are going to set the icon associated with the button as the icon to place on the taskbar:

VB
Private Sub btnIconBlack_Click(ByVal sender As Object, _
        ByVal e As System.Windows.RoutedEventArgs) Handles btnIconBlack.Click
    Me.TaskbarItemInfo.Overlay = CType(Resources("IconBlack"), ImageSource)
End Sub

Private Sub btnIconBlue_Click(ByVal sender As Object, _
        ByVal e As System.Windows.RoutedEventArgs) Handles btnIconBlue.Click
    Me.TaskbarItemInfo.Overlay = CType(Resources("IconBlue"), ImageSource)
End Sub

Private Sub btnIconGreen_Click(ByVal sender As Object, _
        ByVal e As System.Windows.RoutedEventArgs) Handles btnIconGreen.Click
    Me.TaskbarItemInfo.Overlay = CType(Resources("IconGreen"), ImageSource)
End Sub

Private Sub btnIconPink_Click(ByVal sender As Object, _
        ByVal e As System.Windows.RoutedEventArgs) Handles btnIconPink.Click
    Me.TaskbarItemInfo.Overlay = CType(Resources("IconPink"), ImageSource)
End Sub

Private Sub btnIconRed_Click(ByVal sender As Object, _
        ByVal e As System.Windows.RoutedEventArgs) Handles btnIconRed.Click
    Me.TaskbarItemInfo.Overlay = CType(Resources("IconRed"), ImageSource)
End Sub

Private Sub btnIconReset_Click(ByVal sender As Object, _
        ByVal e As System.Windows.RoutedEventArgs) Handles btnIconReset.Click
    Me.TaskbarItemInfo.Overlay = Nothing
End Sub

Well, not too hard, right? At the beginning of the article, create a window resource of type DrawingImage. We then convert this resource to the type ImageSource, which is the expected type of the TaskbarItemInfo Overlay property and assign the result to it. If you press the button that is associated with the fire toy, this is the result:

taskbar_icon.PNG

And now, if we press the Reset Overlay button, our application icon returns to it original state:

taskbar_no_icon.PNG

As you can see, this is a very simple code that opens new ways of communication with our users. We could, for example, display an icon when the application fails, or if it requires user intervention on a task or on new data arrival, as the user need not be looking at the window to know what is happening as they may be checking email, working on an Excel sheet, or just looking at some websites, but would know instantly the need to intervene in our application.

ProgressBar

tab002.PNG

If you think IconOverlay use is easy, using the progress bar on the icon in the taskbar is easier. We will begin by designing the screen:

XML
<TabItem Header="Taskbar ProgressBar" Name="TabItem2">
    <Grid>
        <Grid.Background>
            <ImageBrush ImageSource="pack://application:,,,/WPF Icon Overlay 
                        And ProgressBar;component/images/progressbar.png" 
              Stretch="Uniform" Opacity=".2" />
        </Grid.Background>
        <Grid.RowDefinitions>
            <RowDefinition Height=".25*"></RowDefinition>
            <RowDefinition Height=".25*"></RowDefinition>
            <RowDefinition Height=".25*"></RowDefinition>
            <RowDefinition Height=".25*"></RowDefinition>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" VerticalContentAlignment="Center" 
                 HorizontalContentAlignment="Center" FontSize="24" Foreground="White"
                 Content="Mueve el Slider para Aumentar/Disminuir">
        </Label>
                    
        <ComboBox Grid.Row="1" Name="cmbEstilos" Height="30" 
               Width="Auto" Margin="5" HorizontalAlignment="Stretch" 
               VerticalAlignment="Stretch">
            <ComboBox.Items>
                <ComboBoxItem Name="ItemNormal" Content="Normal"></ComboBoxItem>
                <ComboBoxItem Name="ItemError" Content="Error"></ComboBoxItem>
                <ComboBoxItem Name="ItemStop" Content="Stop"></ComboBoxItem>
                <ComboBoxItem Name="ItemIndeterminate" 
                           Content="Indeterminado"></ComboBoxItem>
                <ComboBoxItem Name="ItemNone" Content="Ninguno"></ComboBoxItem>
            </ComboBox.Items>
        </ComboBox>
                    
        <ProgressBar Grid.Row="2" Name="Pbar" Height="30" Width="Auto" 
              Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Center"
              Minimum="0" Maximum="100" Value="{Binding Path=Value, ElementName=SlidValue}"/>
                    
        <Slider Grid.Row="3" Name="SlidValue" Height="30" Width="Auto" 
              Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Center" 
              Minimum="0" Maximum="100" Value="50" SmallChange="1">
        </Slider>
    </Grid>
</TabItem>

The XAML code is easy. The most remarkable and really useful is the Binding that we have applied to the Value property of ProgressBar. This binding points to the Slider control's Value property. This way, each time we move the slider, we will automatically update the progress bar.

As you can see, there is a combo with several options; these are states that can have the progress bar on the taskbar:

  • Normal The progress bar appears as normal, in green color.
  • Error Same as normal, only this time it appears in red color.
  • Stop The progress bar is stopped and can not move forward, the color is yellow.
  • Indeterminate The bar has an indeterminate progress, making a cyclic animation.
  • None The progress bar is not shown on the taskbar.

A long process in the background may take several minutes, and the user can minimize the application and see the progress and outcome without maximizing the application and while working in another application. You can see when the task has stopped and needs your attention (yellow bar) where there has been an error (red bar), or simply the progress of the task, and see if you have time to make a coffee :). If we combine this with IconOverlay, you will realize the power we get to communicate with our users. They can know the status of the application without even maximizing the window while doing other things; no more downtime watching a progressbar on screen.

The code is also very simple; in the Loaded event, we set the progress bar state to None:

VB
Private Sub MainWindow_Loaded(ByVal sender As Object, _
         ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    Me.TaskbarItemInfo.ProgressState = Shell.TaskbarItemProgressState.None
End Sub

And now, control the valueChanged event of the Slider control to assign the value to our progress bar on the taskbar:

VB
Private Sub SlidValue_ValueChanged(ByVal sender As Object, _
            ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of Double)) 
            Handles SlidValue.ValueChanged
    Me.TaskbarItemInfo.ProgressValue = SlidValue.Value / 100
End Sub

Two things here. First, it is not necessary to have a progressbar on our window to operate the progressbar on the taskbar, but I think it is necessary for the user to have both, and not force them to have to look at the taskbar if they are viewing our window. Second, the property TaskbarItemInfo.ProgressValue has a range of 0 to 1, so we must divide the value of our Slider control or our progress from 100 and remember to always keep values between 0 and 100 to avoid problems.

Finally, we will handle the combobox event SelectionChanged to change our type of progress bar for that indicated in the drop-down:

VB
Private Sub cmbEstilos_SelectionChanged(ByVal sender As Object, _
          ByVal e As System.Windows.Controls.SelectionChangedEventArgs) _
          Handles cmbEstilos.SelectionChanged
    Select Case DirectCast(e.AddedItems(0), System.Windows.Controls.ComboBoxItem).Content
        Case "Normal"
            SlidValue.IsEnabled = True
            Pbar.IsIndeterminate = False
            Me.TaskbarItemInfo.ProgressState = Shell.TaskbarItemProgressState.Normal
        Case "Error"
            SlidValue.IsEnabled = True
            Pbar.IsIndeterminate = False
            Me.TaskbarItemInfo.ProgressState = Shell.TaskbarItemProgressState.Error
        Case "Stop"
            SlidValue.IsEnabled = True
            Pbar.IsIndeterminate = False
            Me.TaskbarItemInfo.ProgressState = Shell.TaskbarItemProgressState.Paused
        Case "Indeterminado"
            SlidValue.IsEnabled = False
            Pbar.IsIndeterminate = True
            Me.TaskbarItemInfo.ProgressState = Shell.TaskbarItemProgressState.Indeterminate
        Case "Ninguno"
            SlidValue.IsEnabled = True
            Pbar.IsIndeterminate = False
            Me.TaskbarItemInfo.ProgressState = Shell.TaskbarItemProgressState.None
    End Select
End Sub

And with that, our application be able to display the progress bar in different styles:

pbar_normal.PNGpbar_error.PNGpbar_stop.PNGpbar_indeterminate.PNG

History

  • 24 July 2010 - Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Freelance Developer
Spain Spain
MVP Windows Platform Development 2014
MVP Windows Phone Development 2013
MVP Windows Phone Development 2012

Comments and Discussions

 
GeneralThank you for this article Pin
Kubajzz24-Jul-10 6:28
Kubajzz24-Jul-10 6:28 
GeneralRe: Thank you for this article Pin
Josué Yeray Julián Ferreiro24-Jul-10 6:52
Josué Yeray Julián Ferreiro24-Jul-10 6:52 
GeneralRe: Thank you for this article Pin
Kubajzz24-Jul-10 8:39
Kubajzz24-Jul-10 8:39 
Thanks a lot for your reply!

I didn't know about that memory-eating problem, thanks for the explanation. I'll keep it in mind next time I use an image in a WPF application.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.