Introduction
In the previous article on integrating our application with the taskbar in Windows 7 (you can see it here), we talked about ways that gives us the Windows 7 taskbar to communicate information to our users, using the overlay of icons and progress bar.
Any program needs two-way communication, on one hand communicate information to the user and on the other users provide our application information with which to work, because we have managed to adapt to Windows 7 the way our users get information, we now make easily and intuitively that our user communicate information to us from the taskbar.
For this, in this article, we will discuss the JumpList and Thumbnail Toolbars:
- Jumplist: The
Jumplist
are quick links to parts of our application that appears when you right click on the icon of it in the taskbar, we can make our app go directly to a particular window, without having started yet.
- Thumbnail Toolbars: When you move the mouse over the icons of active applications, Windows 7 offers a preview of the window of that application, with the Thumbnail Toolbars we can add buttons to that view that execute in our application.
.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 the "use and enjoyment" of these features is far easier. So the code in this article is only useful for .NET 4.
Let's Begin
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
:
<Window.TaskbarItemInfo>
<TaskbarItemInfo/>
</Window.TaskbarItemInfo>
With this, we will have access to many properties of the Windows 7 taskbar easily and quickly.
JumpList
We will start working with JumpList. The first thing we have to do is open the application.xaml code file and add a new event handler for the Startup
event:
Private Sub Application_Startup(ByVal sender As Object,
ByVal e As System.Windows.StartupEventArgs)
Handles Me.Startup
End Sub
The way in which elements of the Jumplist
will communicate with our application is by using arguments passed to the executable on start, so that in the Startup
event will make two jobs, first check if we have received a parameter and run the code associated and in this event we will create our list and notify it to the application.
To handle the arguments passed to the application, will use the Args
property of the e
variable of the event, using a Select Case
block to do so as follows:
If e.Args.Count > 0 Then
Select Case e.Args(0)
Case "update"
MessageBox.Show("No updates needed")
Case "searchclient"
MessageBox.Show("You have picked Clients")
Case "searchinvoice"
MessageBox.Show("You have picked Invoices")
End Select
End If
As you can see, it is very simple. When creating our JumpList
to each element we have an associated argument (update
, searchinvoice
or searchclient
), when selecting an item from the list, that element runs your application sending the argument that we have associated with.
Now we create the elements of the JumpList
. For this, we will use the object JumpTask
from the Shell
namespace:
Dim SearchUpdates As New Shell.JumpTask
SearchUpdates.Title = "Search for Updates"
SearchUpdates.Arguments = "update"
SearchUpdates.Description = "Find new updates for the application"
SearchUpdates.CustomCategory = "Management"
SearchUpdates.IconResourcePath = Assembly.GetEntryAssembly().CodeBase
SearchUpdates.ApplicationPath = Assembly.GetEntryAssembly().CodeBase
Dim SearchClient As New Shell.JumpTask
SearchClient.Title = "Search clients"
SearchClient.Arguments = "searchclient"
SearchClient.Description = "Search the Clients database"
SearchClient.CustomCategory = "Clients"
SearchClient.IconResourcePath = Assembly.GetEntryAssembly().CodeBase
SearchClient.ApplicationPath = Assembly.GetEntryAssembly().CodeBase
Dim SearchInvoice As New Shell.JumpTask
SearchInvoice.Title = "Search Invoice"
SearchInvoice.Arguments = "searchinvoice"
SearchInvoice.Description = "Search the Invoices database"
SearchInvoice.CustomCategory = "Invoices"
SearchInvoice.IconResourcePath = Assembly.GetEntryAssembly().CodeBase
SearchInvoice.ApplicationPath = Assembly.GetEntryAssembly().CodeBase
Simply define the features of each JumpTask
, now we only add them to a JumpList
:
Dim List As New Shell.JumpList
List.JumpItems.Add(SearchUpdates)
List.JumpItems.Add(SearchClient)
List.JumpItems.Add(SearchInvoice)
Finally, we must tell the system to relate this list with your application, using the method SetJumpList
of the class JumpList
:
Shell.JumpList.SetJumpList(Application.Current, List)
Although this code will run whenever you start the application, the system will never duplicate JumpList
elements. Whenever we pass a JumpList
, it updates the elements that are assigned to our application, if we made a change, create new items or remove items no longer exist.
With this, if you run the application and press the right button on the taskbar icon, you will see the elements created by us, if you choose one, you'll see a corresponding message appears and opens a new instance of the application:
Overall, giving our application a JumpList
is not a complicated process, but ultimately it can give us many benefits. What happens to our users for multiple Windows to reach a data query or update, when we can offer more shares common with just two clicks and start your application directly to where our users need to go? If you think about it, sure, can you think of the thousands of situations where you were very comfortable having this system at hand. At least in my personal experience, this is one of the features of Windows 7 that I find most useful.
Thumbnail Toolbars
This way, the user interacts with our application combines seamlessly with the content of our previous article, in which we explained as informing the user of the progress of our application, but having the same window in sight. Well, with thumbnail Toolbars allowed, after receiving this information, the user can respond by executing an order in our application without the need to maximize the window.
The first thing we do is to create images for buttons, using the class DrawingImage
as resources from our window:
<Window.Resources>
<DrawingImage x:Key="IconUpdate">
<DrawingImage.Drawing>
<ImageDrawing Rect="0,0,24,24" ImageSource="/Images/update.png" />
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="IconClient">
<DrawingImage.Drawing>
<ImageDrawing Rect="0,0,24,24" ImageSource="/Images/client.png" />
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="IconInvoice">
<DrawingImage.Drawing>
<ImageDrawing Rect="0,0,24,24" ImageSource="/Images/invoice.png" />
</DrawingImage.Drawing>
</DrawingImage>
</Window.Resources>
The class we will use to create our buttons is the TaskBarItemInfo.ThumbButtonInfo
:
<Window.TaskbarItemInfo>
<TaskbarItemInfo>
<TaskbarItemInfo.ThumbButtonInfos>
<ThumbButtonInfo x:Name="btnUpdate"
ImageSource="{StaticResource IconUpdate}"
Description="Find updates for the application"
IsBackgroundVisible="True">
</ThumbButtonInfo>
<ThumbButtonInfo x:Name="btnClient"
ImageSource="{StaticResource IconClient}"
Description="Search Clients"
IsBackgroundVisible="True">
</ThumbButtonInfo>
<ThumbButtonInfo x:Name="btnInvoice"
ImageSource="{StaticResource IconInvoice}"
Description="Search Invoices"
IsBackgroundVisible="True">
</ThumbButtonInfo>
</TaskbarItemInfo.ThumbButtonInfos>
</TaskbarItemInfo>
</Window.TaskbarItemInfo>
ThumbButtonInfo
class has several properties that allow us to customize the look of our button:
Description
: Indicates the text that appears on the button to leave the mouse over it.
IsInteractive
: This property allows you to use a button in two ways:
True
: The button behaves like a normal button, this is the default behavior.
False
: The interactive button is only shown to the user, not reacting to the actions of this.
IsBackgroundVisible
: Indicates whether the button is highlighted by positioning the mouse over it or not, the default is True
.
DismissWhenClicked
: If we set this property to True
, when you press the button on, the Thumbnail will close, if False
, it remains open until you leave the mouse icon on the taskbar, the default is False
.
We have created our buttons. If you run the application and pass the mouse over the icon on the taskbar, you'll see three buttons appear that we have created, but if you click on them, nothing happens.
Now we set the behavior of buttons, this can be done in two ways: using events as any other button or by using commands.
The two methods can do the same job but perhaps is more advisable to use commands, as a rule these buttons will be the same as other buttons positioned on the main application toolbar or menu options and commands using the same code can link the two. I'll explain the two cases a bit more.
Using Events
The operation of the ThumbnailButtonInfo
with events is very simple and exactly like the other controls in your application, simply add the event to which we respond from XAML:
<Window.TaskbarItemInfo>
<TaskbarItemInfo>
<TaskbarItemInfo.ThumbButtonInfos>
<ThumbButtonInfo x:Name="btnUpdate"
ImageSource="{StaticResource IconUpdate}"
Description="Find updates for the application"
IsBackgroundVisible="True"
Click="btnUpdate_Click">
</ThumbButtonInfo>
<ThumbButtonInfo x:Name="btnClient"
ImageSource="{StaticResource IconClient}"
Description="Search Clients"
IsBackgroundVisible="True"
Click="btnClient_Click">
</ThumbButtonInfo>
<ThumbButtonInfo x:Name="btnInvoice"
ImageSource="{StaticResource IconInvoice}"
Description="Search Invoices"
IsBackgroundVisible="True"
Click="btnInvoice_Click">
</ThumbButtonInfo>
</TaskbarItemInfo.ThumbButtonInfos>
</TaskbarItemInfo>
</Window.TaskbarItemInfo>
As you can see, on each button we added a click event, now in code write the code needed for each event handler:
Private Sub btnUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
MessageBox.Show("Click on Update using events")
End Sub
Private Sub btnClient_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
MessageBox.Show("Click on Clients using events")
End Sub
Private Sub btnInvoice_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
MessageBox.Show("Click on invoice using events")
End Sub
With this, if we run our application and click on the buttons, the appropriate messagebox
appears:
Using Commands
This method involves a little more work, but it is much more representative of what an application would be doing. The first step is to create a new class for each button:
As you can see, we have created a class for every action that we perform: Client
, Invoice
and Update
. These classes must implement the ICommand
interface to be used as commands in our application:
Public Class UpdateCommand
Implements ICommand
Public Function CanExecute(ByVal parameter As Object) As Boolean
Implements ICommand.CanExecute
Return True
End Function
Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Implements ICommand.CanExecuteChanged
Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
MessageBox.Show("Click on update button using Commands")
End Sub
End Class
Public Class ClientCommand
Implements ICommand
Public Function CanExecute(ByVal parameter As Object) As Boolean
Implements ICommand.CanExecute
Return True
End Function
Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Implements ICommand.CanExecuteChanged
Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
MessageBox.Show("Click on Clients Buttons using Commands")
End Sub
End Class
Public Class InvoiceCommand
Implements ICommand
Public Function CanExecute(ByVal parameter As Object) As Boolean
Implements ICommand.CanExecute
Return True
End Function
Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Implements ICommand.CanExecuteChanged
Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
MessageBox.Show("Click on Invoice Button Using Commands")
End Sub
End Class
Next, what we need to do is have a common place from which to expose our commands, so that we can use the ViewModel
, add a new class file to your project, called ViewModel
and give it the following code:
Public Class ViewModel
Private _UpdateCommand As UpdateCommand = New UpdateCommand()
Private _ClientCommand As ClientCommand = New ClientCommand()
Private _InvoiceCommand As InvoiceCommand = New InvoiceCommand()
Public ReadOnly Property UpdateCommand As ICommand
Get
Return _UpdateCommand
End Get
End Property
Public ReadOnly Property ClientCommand As ICommand
Get
Return _ClientCommand
End Get
End Property
Public ReadOnly Property InvoiceCommand As ICommand
Get
Return _InvoiceCommand
End Get
End Property
End Class
Our ViewModel
simply exposes public
properties of the type of our commands to the view layer, the XAML in this case, so we just have to reference this in our XAML ViewModel
and our DataContext
:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:WPF_JumpList_And_Thumbnail_Toolbars"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<viewModel:ViewModel></viewModel:ViewModel>
</Window.DataContext>
</Window>
Finally, we only need to link our buttons with their respective commands. For this, we will use the property Command
of each ThumbButtonInfo
:
<ThumbButtonInfo x:Name="btnUpdate"
ImageSource="{StaticResource IconUpdate}"
Description="Comprueba actualizaciones"
IsBackgroundVisible="True"
Command="{Binding UpdateCommand}">
</ThumbButtonInfo>
<ThumbButtonInfo x:Name="btnClient"
ImageSource="{StaticResource IconClient}"
Description="Ver los clientes"
IsBackgroundVisible="True"
Command="{Binding ClientCommand}">
</ThumbButtonInfo><ThumbButtonInfo x:Name="btnInvoice"
ImageSource="{StaticResource IconInvoice}"
Description="Ver las facturas"
IsBackgroundVisible="True"
Command="{Binding InvoiceCommnad}">
</ThumbButtonInfo>
As you can see, we are simply Binding to our command. If you execute the application again and you click a button, you can see that the effect is the same as with the events, only this time our code is more reusable and more orderly, it can share between multiple windows or controls the same command and keeping the same functionality:
History
- 03 August 2010 - First version