Share via


Exercise: Experiment with the New Windows 7 Taskbar Features

In this exercise, you will experiment with the new Windows 7 taskbar features. You will extend a showcase application that demonstrates the use of the new taskbar functionality to provide a taskbar progress bar, overlay icon, custom thumbnail, jump list and more. Most of the application’s user interface is already implemented; you will have to fill in the missing parts to interact with the Windows 7 taskbar using the Windows API Code Pack.

To begin this exercise, open the TaskbarConcepts_Starter solution (under the HOL root folder) in Visual Studio.

C# VB

Figure 2

Taskbar Concepts solution structure in Visual Studio

Spend a minute or two exploring the XAML and C# or VB files that comprise the demo application. For your convenience, ensure that the Task List tool window is visible (in the View menu, choose Task List) and in the tool window’s combo box select Comments—you will now see TODO items for each of the tasks in this exercise.

Note:
Help

 In the interests of brevity and simplicity, the demo application does not demonstrate best practices of WPF UI development, nor does it exhibit the best design guidelines for working with the Windows 7 Taskbar. For more information, consult the Windows 7 User Experience Guidelines (Taskbar) at https://msdn.microsoft.com/en-us/library/aa511446.aspx and the Taskbar Extensions article at https://msdn.microsoft.com/en-us/library/dd378460(VS.85).aspx

Task 1—Using Taskbar Overlay Icons

In this task, you will toggle an overlay icon on the application’s taskbar button when an icon is selected by the user.

  1. Navigate to the Overlays.xaml.cs (C#) or Overlays.xaml.vb (VB) code file and locate the ShowOrHideOverlayIcon method.
  2. In the method’s code, check whether the ShowOverlay checkbox is checked.
  3. If the checkbox is checked, retrieve the currently selected icon from the list using the iconsList.SelectedItem property, and if it is not null, pass it to the TaskbarManager.Instance.SetOverlayIcon method along with an appropriate textual description.

    This will cause an overlay icon to appear in the bottom-right corner of the application’s taskbar button, providing an immediate status indicator without the need to switch to the application’s window. This feature is used by Windows Live Messenger to display online availability status, by Microsoft Office Outlook 14 to display the new mail notification and by many other applications.

  4. If the checkbox is not checked, pass null to the same method to clear the overlay icon. (You may also pass null for the textual description.)
  5. The complete code should be similar to the following:if (ShowOverlay.IsChecked.Value)
    {
    Icon icon = iconsList.SelectedItem as Icon;
    if (icon != null)
    TaskbarManager.Instance.SetOverlayIcon( icon, "icon" + iconsList.SelectedIndex.ToString());
    }
    else
    {
    TaskbarManager.Instance.SetOverlayIcon(null, null);
    }

    If ShowOverlay.IsChecked.Value Then
    Dim icon As Icon = TryCast(iconsList.SelectedItem, Icon)
    If icon IsNot Nothing Then
    TaskbarManager.Instance.SetOverlayIcon(icon, "icon" & _
    iconsList.SelectedIndex.ToString())
    End If
    Else
    TaskbarManager.Instance.SetOverlayIcon(Nothing, Nothing)
    End If

  6. Compile and run the application.
  7. Navigate to the Overlay Icon tab, check the checkbox and make sure that an overlay icon appears on the application’s taskbar button. For example:

    Figure 3

    Taskbar overlay icon shown when the ‘Show selected icon as overlay’ checkbox is checked

  8. Select another icon and make sure that the overlay icon changes.
  9. Clear the checkbox and make sure that the overlay icon is cleared as well.

Task 2—Using Taskbar Progress Bars

In this task, you will set the state and value of the application’s taskbar progress bar when the user selects the progress state from a combo box or changes the value by using a slider.

  1. Navigate to the ProgressBar.xaml.cs(C#) orProgressBar.xaml.vb (VB)code file and locate the UpdateProgress method.
  2. In the method’s code, check whether the ShowProgressBar checkbox is checked.
  3. If the checkbox is checked, use the TaskbarManager.Instance.SetProgressValue method to set the progress value to the value of the progressSlider.Value property. Use the number 100 for the maximum progress value.
  4. If the checkbox is checked, use the TaskbarManager.Instance.SetProgressState method to set the progress state to the value of the ProgressStateSelection.SelectedItem property.

    This will cause a progress bar to appear in the application’s taskbar button, providing an immediate progress indicator without the need to switch to the application’s main window. This feature is extensively used by Windows Explorer when performing file operations, by Internet Explorer when downloading files and by other Windows applications.

  5. If the checkbox is not checked, use the method from the previous step to set the progress state to TaskbarProgressState.NoProgress, clearing the progress bar.
  6. The complete code should be similar to the following:if (ShowProgressBar.IsChecked.Value)
    {
    TaskbarManager.Instance.SetProgressValue((int)progressSlider.Value, 100);
    TaskbarManager.Instance.SetProgressState( (TaskbarProgressBarState)ProgressStateSelection.SelectedItem);
    }
    else
    {
    TaskbarManager.Instance.SetProgressState( TaskbarProgressBarState.NoProgress);
    }

    If ShowProgressBar.IsChecked.Value Then
    TaskbarManager.Instance.SetProgressValue(CInt(Fix(progressSlider.Value)), _
    100)
    TaskbarManager.Instance.SetProgressState( _
    CType(ProgressStateSelection.SelectedItem, _
    TaskbarProgressBarState))
    Else
    TaskbarManager.Instance.SetProgressState( _
    TaskbarProgressBarState.NoProgress)
    End If

  7. Navigate to the ProgressStateSelection_SelectionChanged method.
  8. In the method’s code, check whether the ProgressStateSelection.SelectedItem property is equal to TaskbarProgressState.NoProgress.
  9. If it is equal, set the ShowProgressBar.IsChecked property to false.
  10. Otherwise, set the same property to true.
  11. Finally, call the UpdateProgress method you wrote earlier to update the taskbar progress state and value if necessary.
  12. The complete code should be similar to the following:if ((TaskbarProgressBarState)ProgressStateSelection.SelectedItem == TaskbarProgressBarState.NoProgress)
    {
    ShowProgressBar.IsChecked = false;
    }
    else
    {
    ShowProgressBar.IsChecked = true;
    }
    UpdateProgress();

If CType(ProgressStateSelection.SelectedItem, TaskbarProgressBarState) = _ TaskbarProgressBarState.NoProgress Then
ShowProgressBar.IsChecked = False
Else
ShowProgressBar.IsChecked = True
End If
UpdateProgress()

  1. Navigate to the ShowProgressBar_Click method.
  2. In the method’s code, check whether the ShowProgressBar.IsChecked property is true.
  3. If it is, set the ProgressStateSelection.SelectedItem property to TaskbarProgressState.Normal.
  4. Otherwise, set the same property to TaskbarProgressState.NoProgress.
  5. Finally, call the UpdateProgress method you wrote earlier to update the taskbar progress state and value if necessary.
  6. The complete code should be similar to the following:if (ShowProgressBar.IsChecked.Value)
    {
    ProgressStateSelection.SelectedItem = TaskbarProgressBarState.Normal;
    }
    else
    {
    ProgressStateSelection.SelectedItem = TaskbarProgressBarState.NoProgress;
    }
    UpdateProgress();

If ShowProgressBar.IsChecked.Value Then
ProgressStateSelection.SelectedItem = TaskbarProgressBarState.Normal
Else
ProgressStateSelection.SelectedItem = TaskbarProgressBarState.NoProgress
End If
UpdateProgress()

  1. Compile and run the application.
  2. Navigate to the Progress Bar tab, check the checkbox and move the slider to the middle. Make sure that a taskbar progress bar is displayed and updated accordingly. For example:

    Figure 4

    Taskbar progress bar reflects the slide value when the ‘Show slider’s value in progress bar’ checkbox is checked

  3. Select a different progress state from the combo box and make sure the progress state changes (for example, the Error progress state corresponds to a red progress bar).

    Figure 5

    Taskbar progress indicator reflects the progress state selected in the combo box, in this case—‘Error’

  4. Clear the checkbox and make sure the progress bar is cleared as well.

Task 3—Using Thumbnail Toolbars

In this task, you will create taskbar thumbnail toolbar buttons to navigate images displayed in the main application window.

  1. Navigate to the ToolbarButtons.xaml.cs(C#) or ToolbarButtons.xaml.vb (VB) code file and locate the CreateToolbarButtons method. You will create four thumbnail toolbar buttons for image navigation, and add these buttons to the application’s thumbnail toolbar. As a result, the user will be able to navigate the images from the taskbar thumbnail, without switching to the application’s main window.

    Thumbnail toolbars are used by Windows Media Player to provide convenient navigation between tracks in the current playlist without switching to the Media Player window. This effectively replaces the need for the Media Player taskbar desk-band, which introduced clutter into the Windows taskbar and consumed a significant amount of screen estate that can be used for taskbar buttons.

    Figure 6

    The Windows Media Player thumbnail toolbar

  2. In the method’s code, assign the buttonFirst member variable with a new instance of the ThumbnailToolbarButton class. Pass to the constructor the TaskbarConcepts.Resources.first image and the string “First Image” as the tooltip.
  3. Set the buttonFirst.Enabled property to false.
  4. Register the buttonFirst_Click method to the buttonFirst.Click event.
  5. Repeat steps 2-4 for the buttonPrevious member variable with the TaskbarConcepts.Resources.prevArrow image and the string “Previous Image”.
  6. Repeat steps 2 and 4 (without step 3) for the buttonNext member variable with the TaskbarConcepts.Resources.nextArrow image and the string “Next Image”.
  7. Repeat steps 2 and 4 (without step 3) for the buttonLast member variable with the TaskbarConcepts.Resources.last image and the string “Last Image”.
  8. Call the TaskbarManager.Instance.ThumbnailToolbars.AddButtons method, passing the application’s main window handle as the first parameter, followed by the buttons created in the previous steps. This step creates the taskbar thumbnail toolbar.
  9. The complete code should be similar to the following:buttonFirst = new ThumbnailToolbarButton( TaskbarConcepts.Resources.first, "First Image");
    buttonFirst.Enabled = false;
    buttonFirst.Click += buttonFirst_Click;

    buttonPrevious = new ThumbnailToolbarButton( TaskbarConcepts.Resources.prevArrow, "Previous Image");
    buttonPrevious.Enabled = false;
    buttonPrevious.Click += buttonPrevious_Click;

    buttonNext = new ThumbnailToolbarButton( TaskbarConcepts.Resources.nextArrow, "Next Image");
    buttonNext.Click += buttonNext_Click;

    buttonLast = new ThumbnailToolbarButton( TaskbarConcepts.Resources.last, "Last Image");
    buttonLast.Click += buttonLast_Click;

    TaskbarManager.Instance.ThumbnailToolbars.AddButtons(
    new WindowInteropHelper(Application.Current.MainWindow).Handle,
    buttonFirst, buttonPrevious, buttonNext, buttonLast);

buttonFirst = New ThumbnailToolbarButton(TaskbarConcepts.Resources.first, _ "First Image")
buttonFirst.Enabled = False
buttonFirst.Click += buttonFirst_Click

buttonPrevious = New ThumbnailToolbarButton(TaskbarConcepts.Resources.prevArrow, "Previous Image")
buttonPrevious.Enabled = False
buttonPrevious.Click += buttonPrevious_Click

buttonNext = New ThumbnailToolbarButton(TaskbarConcepts.Resources.nextArrow, _ "Next Image")
buttonNext.Click += buttonNext_Click

buttonLast = New ThumbnailToolbarButton(TaskbarConcepts.Resources.last, _ "Last Image")
buttonLast.Click += buttonLast_Click

TaskbarManager.Instance.ThumbnailToolbars.AddButtons(New WindowInteropHelper(Application.Current.MainWindow).Handle, buttonFirst, _ buttonPrevious, buttonNext, buttonLast)

  1. Compile and run the application.
  2. Navigate to the Thumbnail Toolbar tab and ensure that there are images shown. If there are no images, make sure your Pictures library contains a few images.
  3. Hover over the application’s taskbar button until the thumbnail is shown. Use the four thumbnail toolbar buttons to navigate between the images. For example:

    Figure 7

    Thumbnail toolbar allows navigation between images while hovering over the application’s thumbnail

Task 4—Using Live Thumbnail Previews

In this task, you will customize live thumbnails (and previews) of the application’s window and provide the displayed thumbnail lazily (on demand).

  1. Navigate to the Thumbnail.xaml.cs(C#) or Thumbnail.xaml.vb (VB) code file and locate the createOnDemandThumbnail_Click method.
  2. In the method’s code, check whether the trickyBorder visual element has a thumbnail preview. You can use the Utilities.HasThumbnailPreview method for this purpose.
  3. If it doesn’t have a preview yet, continue to the following steps. Otherwise, return from the method—there is already a thumbnail for this element and there’s no need to create it again.
  4. Calculate the offset of the trickyBorder visual element from the application’s main window (you can retrieve the main window frame using the Application.Current.MainWindow property). To calculate the offset, you can use the helper method Utilities.GetOffset.

    The reason for calculating the offset is that we want the actual taskbar thumbnail to display only the image itself, and not the entire window frame. In this case, the taskbar thumbnail APIs require the offset from the application’s main window frame to be specified. Thumbnail customization can be useful if you want to draw attention to a specific part of the window when it’s displayed as a thumbnail, or when you want to dynamically decide which part of the window to display in the thumbnail. Technically, it’s not binding for you to display a part of your window in the thumbnail—you could provide a completely custom image—but this has the potential to confuse users.

    Figure 8

    Internet Explorer 8 features tabbed thumbnails of its TDI interface

  5. Create a new instance of the TabbedThumbnail class and pass to its constructor the application’s main window, the trickyBorder visual element and the offset calculated in the previous step.
  6. Use the TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview method to add the newly created preview object to the taskbar.
  7. Register for the TabbedThumbnailBitmapRequested event of the TabbedThumbnail instance using the TabbedThumbnail_TabbedThumbnailBitmapRequested method. This means that we are not providing the thumbnail bitmap statically; instead, the DWM will call back into our event implementation so that we provide the bitmap dynamically, only when it’s needed.
  8. Set the Tooltip property of the TabbedThumbnail instance to a string of your choice.
  9. The complete code should be similar to the following:if (!Utilities.HasThumbnailPreview(trickyBorder))
    {
    Vector offset = Utilities.GetOffset( Application.Current.MainWindow, trickyBorder);
    TabbedThumbnail preview = new TabbedThumbnail( Application.Current.MainWindow, trickyBorder, offset);
    TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(preview);

    preview.TabbedThumbnailBitmapRequested += TabbedThumbnail_TabbedThumbnailBitmapRequested;

    preview.Tooltip = "This bitmap is created and returned on demand";
    }

If Not Utilities.HasThumbnailPreview(trickyBorder) Then
Dim offset As Vector = _ Utilities.GetOffset(Application.Current.MainWindow, trickyBorder)
Dim preview As New TabbedThumbnail(Application.Current.MainWindow, _ trickyBorder, offset)
TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(preview)

preview.TabbedThumbnailBitmapRequested += _ TabbedThumbnail_TabbedThumbnailBitmapRequested

preview.Tooltip = "This bitmap is created and returned on demand"
End If

  1. Navigate to the removeOnDemandThumbnail_Click method.
  2. In the method’s code, retrieve the TabbedThumbnail object corresponding to the trickyBorder visual element’s thumbnail using the TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview method.
  3. If the retrieved instance is not null, use the TaskbarManager.Instance.TabbedThumbnail.RemoveThumbnailPreview method to remove the thumbnail preview.
  4. The complete code should be similar to the following:TabbedThumbnail preview = TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview(trickyBorder);
    if (preview != null)
    TaskbarManager.Instance.TabbedThumbnail.RemoveThumbnailPreview(preview);

Dim preview As TabbedThumbnail = _ TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview(trickyBorder)
If preview IsNot Nothing Then
TaskbarManager.Instance.TabbedThumbnail.RemoveThumbnailPreview(preview)
End If

  1. Navigate to the TabbedThumbnail_TabbedThumbnailBitmapRequested method.
  2. In the method’s code, check whether the _sneakySource member variable is null.
  3. If it is, assign to it a new BitmapImage object, call its BeginInit method, set its DecodePixelHeight property to the number 200, set its UriSource property to a new Uri instance initialized with the string “pack://application:,,,/assets/SpeedyGonzalez.jpg” and then call its EndInit method.
  4. Finally, use the TabbedThumbnail.SetImage method of the event arguments parameter and pass to it the _sneakySource member variable.
  5. The complete code should be similar to the following:if (_sneakySource == null)
    {
    _sneakySource = new BitmapImage();
    _sneakySource.BeginInit();
    _sneakySource.DecodePixelHeight = 200;
    _sneakySource.UriSource = new Uri("pack://application:,,,/assets/SpeedyGonzales.jpg");
    _sneakySource.EndInit();
    }
    e.TabbedThumbnail.SetImage(_sneakySource);

If _sneakySource Is Nothing Then
_sneakySource = New BitmapImage()
_sneakySource.BeginInit()
_sneakySource.DecodePixelHeight = 200
_sneakySource.UriSource = New Uri("pack://application:,,,/assets/SpeedyGonzales.jpg")
_sneakySource.EndInit()
End If
e.TabbedThumbnail.SetImage(_sneakySource)
  1. Navigate to the createThumbnail_Click method. In this method, we will use a statically set bitmap for the thumbnail, without registering for the event that is invoked by the DWM. As a result, we will have to manually invalidate the thumbnail whenever it becomes stale.
  2. Repeat steps 2-8 for the image visual element, but this time do not register for the TabbedThumbnailBitmapRequested event. Instead, call the TaskbarManager.Instance.TabbedThumbnail.SetActiveTab method and pass to it the newly created TabbedThumbnail instance.
  3. The complete code should be similar to the following:if (!Utilities.HasThumbnailPreview(image))
    {
    Vector offset = Utilities.GetOffset( Application.Current.MainWindow, image);
    TabbedThumbnail preview = new TabbedThumbnail( Application.Current.MainWindow, image, offset);
    TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(preview);
    preview.Tooltip = "This image will be replaced and invalidated";
    TaskbarManager.Instance.TabbedThumbnail.SetActiveTab(preview);
    }

If Not Utilities.HasThumbnailPreview(image) Then
Dim offset As Vector = _ Utilities.GetOffset(Application.Current.MainWindow, image)
Dim preview As New TabbedThumbnail(Application.Current.MainWindow, _ image, offset)
TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(preview)
preview.Tooltip = "This image will be replaced and invalidated"
TaskbarManager.Instance.TabbedThumbnail.SetActiveTab(preview)
End If

  1. Navigate to the removeThumbnail_Click method.
  2. Repeat steps 10-12 for the image visual element.
  3. The complete code should be similar to the following:TabbedThumbnail preview = TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview(image);
    if (preview != null)
    TaskbarManager.Instance.TabbedThumbnail.RemoveThumbnailPreview(preview);

Dim preview As TabbedThumbnail = _ TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview(image)
If preview IsNot Nothing Then
TaskbarManager.Instance.TabbedThumbnail.RemoveThumbnailPreview(preview)
End If

  1. Navigate to the invalidateThumbnail_Click method. The invalidation is necessary because we did not register an event handler for the thumbnail bitmap, and therefore the bitmap remains static until we explicitly invalidate it.
  2. In the method’s code, check whether there is a thumbnail preview for the image visual element (see steps 11-12 for an example).
  3. If there is, use the InvalidatePreview method of the resulting TabbedThumbnail object to invalidate the thumbnail preview.
  4. The complete code should be similar to the following:TabbedThumbnail preview =
    TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview(image);
    if (preview != null)
    preview.InvalidatePreview();

Dim preview As TabbedThumbnail = _ TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview(image)
If preview IsNot Nothing Then
preview.InvalidatePreview()
End If

  1. Compile and run the application.
  2. Navigate to the Thumbnail Preview tab and click the ‘Add as thumbnail’ button in the ‘Thumbnail with Callback’ group.
  3. Hover over the application’s taskbar button and ensure that the thumbnail displays an image instead of the black rectangle. Hover over the thumbnail and ensure that the live preview also displays the same image instead of the black rectangle. For example:

    Figure 9

    Live thumbnail and live preview showing an image generated on-demand instead of the black rectangle in the application’s window

  4. Click the ‘Remove thumbnail’ button in the ‘Thumbnail with Callback’ group and ensure that the application’s taskbar thumbnail and live preview are back to the default (the entire window).
  5. Click the ‘Add as thumbnail’ button in the ‘Tabbed Thumbnail’ group.
  6. Hover over the application’s taskbar button and ensure that the thumbnail and live preview reflect the current image in the main window.
  7. Click the ‘Update image’ button in the ‘Tabbed Thumbnail’ group and notice that the thumbnail is not refreshed—it still displays the previous image. For example:

    Figure 10

    The thumbnail is not automatically refreshed (because it is not generated on demand), and shows a stale image that doesn’t reflect the UI unless explicitly invalidated

  8. Click the ‘Invalidate thumbnail’ button in the ‘Tabbed Thumbnail’ group and ensure that the thumbnail is updated to reflect the new image.
  9. Finally, click the ‘Remove thumbnail’ button in the ‘Tabbed Thumbnail’ group and ensure that the application’s taskbar thumbnail and live preview are back to the default (the entire window).

Task 5—Using Thumbnail Clips

In this task, you will set a clipping rectangle that will be shown in the window’s taskbar thumbnail in order to zoom in on the relevant part of the window.

  1. Navigate to the ThumbnailClip.xaml.cs(C#) orThumbnailClip.xaml.vb(VB)code file and locate the mediaElement_MediaOpened method.
  2. In the method’s code, calculate the offset of the mediaElement visual element from the main window frame (you can retrieve the main window frame using the Application.Current.MainWindow property). To calculate the offset, you can use the helper method Utilities.GetOffset.
  3. Retrieve the main window’s handle using the WindowInteropHelper class.
  4. Create a clipping rectangle (a System.Drawing.Rectangle object). Initialize its x,y coordinates with the coordinates of the offset calculated in step 2, and initialize its height and width to the height and width of the mediaElement.
  5. Use the Dispatcher.BeginInvoke class to set the thumbnail clip in the background, by using the TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip method and pass to it the main window’s handle from step 3 and the clipping rectangle from step 4.

    Clipped thumbnails are useful when you want to focus on a specific section of your window, and you don’t want to create a custom thumbnail handler for this purpose and draw the thumbnail yourself. For example, a text editor might benefit from a thumbnail clip that shows several lines around the current cursor position—this would be more readable than the entire text editor window.

  6. The complete code should be similar to the following:Vector offset = Utilities.GetOffset( Application.Current.MainWindow, (Visual)mediaElement);

    Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
    {
    IntPtr mainWindowHandle = new WindowInteropHelper( Application.Current.MainWindow).Handle;
    System.Drawing.Rectangle clipRect = new System.Drawing.Rectangle(
    (int)offset.X, (int)offset.Y, (int)mediaElement.ActualWidth, (int)mediaElement.ActualHeight);

    TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip( mainWindowHandle, clipRect);
    }));

Private offset As Vector = Utilities.GetOffset( _ Application.Current.MainWindow, CType(mediaElement, Visual))

Dispatcher.BeginInvoke(DispatcherPriority.Background, New Action( _

Function() AnonymousMethod1()))

Private Function AnonymousMethod1() As Object
Dim mainWindowHandle As IntPtr = New _ WindowInteropHelper(Application.Current.MainWindow).Handle
Dim clipRect As New System.Drawing.Rectangle(CInt(Fix(offset.X)), _ CInt(Fix(offset.Y)), CInt(Fix(mediaElement.ActualWidth)), _ CInt(Fix(mediaElement.ActualHeight)))
TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip( _ mainWindowHandle, clipRect)
Return Nothing
End Function

  1. Compile and run the application.
  2. Navigate to the Thumbnail Clip tab and click the button to select a video file (you can download one from the Internet or use the video under the Sample Videos folder on your machine).
  3. While the video is playing, hover over the application’s taskbar button and ensure that the thumbnail displays only a part of the window, roughly clipped to the video area. For example:

    Figure 11

    Thumbnail clipping ensures that only the relevant parts of the window are shown in the taskbar thumbnail

Task 6—Using Taskbar Jump Lists

In this task, you will add the functionality to support adding user tasks, custom categories and destinations to the application’s jump list, as well as clearing the list of user tasks.

  1. Navigate to the JL.xaml.cs(C#) orJL.xaml.vb (VB)code file and locate the OnAddTasks method.
  2. In the method’s code, create an instance of the JumpListLink class and pass to its constructor the path to notepad.exe (use the Environment.GetFolderPath method to determine the location of the System32 directory in which the Notepad executable resides), and the string “Open Notepad” for the link’s title.
  3. Set the IconReference property of the newly created instance to a new instance of the IconReference class, and pass to the constructor the path to notepad.exe (obtained in the previous step), and the number 0 as the icon index.
  4. Repeat steps 2 and 3 to create links to calc.exe and mspaint.exe with the corresponding “Open Calculator” and “Open Paint” title strings.
  5. Call the JumpList.AddUserTasks method and pass to it the Notepad and Calculator link objects, followed by a new instance of JumpListSeparator, followed by the Paint link object.

    As a result, you’ve added common user tasks to your application’s jump list. In practice, it would be uncommon for an application to include user tasks that launch unrelated applications. Instead, common user tasks would include launching the application with different command line arguments, navigating to a specific area in the application, or even specifying commands for a running instance of the application. For example, Windows Live Messenger uses jump list tasks for changing the user’s online availability status.

    Figure 12

    The Windows Live Messenger taskbar jump list, featuring user tasks

  6. Finally, call the JumpList.Refresh method to refresh the application’s jump list.
  7. The complete code should be similar to the following:string systemFolder = Environment.GetFolderPath( Environment.SpecialFolder.System);

    IJumpListTask notepadTask = new JumpListLink( System.IO.Path.Combine(systemFolder, "notepad.exe"), "Open Notepad")
    {
    IconReference = new IconReference( Path.Combine(systemFolder, "notepad.exe"), 0)
    };
    IJumpListTask calcTask = new JumpListLink( Path.Combine(systemFolder, "calc.exe"), "Open Calculator")
    {
    IconReference = new IconReference( Path.Combine(systemFolder, "calc.exe"), 0)
    };
    IJumpListTask paintTask = new JumpListLink( Path.Combine(systemFolder, "mspaint.exe"), "Open Paint")
    {
    IconReference = new IconReference( Path.Combine(systemFolder, "mspaint.exe"), 0)
    };

    JumpList.AddUserTasks( notepadTask, calcTask, new JumpListSeparator(), paintTask);
    JumpList.Refresh();

Dim systemFolder As String = _ Environment.GetFolderPath(Environment.SpecialFolder.System)

Dim notepadTask As IJumpListTask = New _ JumpListLink(System.IO.Path.Combine(systemFolder, "notepad.exe"), _
"Open Notepad") With {.IconReference = New _ IconReference(Path.Combine(systemFolder, "notepad.exe"), 0)}
Dim calcTask As IJumpListTask = New JumpListLink(Path.Combine(systemFolder, _ "calc.exe"), "Open Calculator") With {.IconReference = New _ IconReference(Path.Combine(systemFolder, "calc.exe"), 0)}
Dim paintTask As IJumpListTask = New JumpListLink(Path.Combine(systemFolder, _ "mspaint.exe"), "Open Paint") With {.IconReference = New _ IconReference(Path.Combine(systemFolder, "mspaint.exe"), 0)}

JumpList.AddUserTasks(notepadTask, calcTask, New JumpListSeparator(), _ paintTask)
JumpList.Refresh()

  1. Navigate to the JumpList property.
  2. In the property’s get accessor, check if the _jumpList member variable is null.
  3. If it is, set its value to the result of the JumpList.CreateJumpList method, set its KnownCategoryToDisplay property to JumpListKnownCategoryType.Recent if the showRecent.IsChecked property is true or JumpListKnownCategoryType.Frequent if it’s false; finally, call the JumpList.Refresh method to refresh the jump list.

    There are two system categories that you can opt in to use by default: the Recent category, which shows documents most recently accessed by your application, and the Frequent category, which shows documents most frequently accessed. Using both categories is discouraged and the managed wrapper doesn’t allow it at all.

    Note:
    Help

    In order to have items appear in the Recent or Frequent categories, your application needs a properly defined file-type association in the Windows Registry (although it does not have to be the default handler for that file-type). The sample application can be registered to handle PNG image files. For more information about file-type associations, consult https://msdn.microsoft.com/en-us/library/dd758090.aspx
  4. Return the value of the _jumpList member variable from the get accessor.
  5. The complete code should be similar to the following:if (_jumpList == null)
    {
    _jumpList = JumpList.CreateJumpList();
    _jumpList.KnownCategoryToDisplay =
    showRecent.IsChecked.Value ? JumpListKnownCategoryType.Recent : JumpListKnownCategoryType.Frequent;
    _jumpList.Refresh();
    }
    return _jumpList;

If _jumpList Is Nothing Then
_jumpList = JumpList.CreateJumpList()
_jumpList.KnownCategoryToDisplay = If(showRecent.IsChecked.Value, _ JumpListKnownCategoryType.Recent, JumpListKnownCategoryType.Frequent)
_jumpList.Refresh()
End If
Return _jumpList

  1. Navigate to the showRecent_Click method.
  2. In the method’s code, set the JumpList.KnownCategoryToDisplay property according to the same logic as in step 10 above, and call the JumpList.Refresh method.
  3. The complete code should be similar to the following:JumpList.KnownCategoryToDisplay =
    showRecent.IsChecked.Value ?
    JumpListKnownCategoryType.Recent : JumpListKnownCategoryType.Frequent;
    JumpList.Refresh();

JumpList.KnownCategoryToDisplay = If(showRecent.IsChecked.Value, _ JumpListKnownCategoryType.Recent, JumpListKnownCategoryType.Frequent)
JumpList.Refresh()

  1. Navigate to the OnClearTasks method.
  2. In the method’s code, call the JumpList.ClearAllUserTasks method to clear the jump list from all user tasks.
  3. Call the JumpList.Refresh method for the changes to take effect.
  4. The complete code should be similar to the following:JumpList.ClearAllUserTasks();
    JumpList.Refresh();

JumpList.ClearAllUserTasks()
JumpList.Refresh()

  1. Navigate to the createCategory_Click method.
  2. In the method’s code, assign to the _currentCategory member variable a new instance of the JumpListCustomCategory class, passing to its constructor the name of the category obtained from the txtCategory member variable.

    Custom categories are an advanced feature that can be used by an application to provide more than just the Recent or Frequent system categories. For example, an email application might provide Inbox, Follow-up and other custom categories in which messages are grouped.

  3. Use the JumpList.AddCustomCategories method and pass to it the newly created category.
  4. Call the JumpList.Refresh method to commit the changes.
  5. Set the IsEnabled property of the createCategoryItem, createCategoryLink, txtCategoryItem and txtCategoryLink member variables to true.
  6. The complete code should be similar to the following:_currentCategory = new JumpListCustomCategory(this.txtCategory.Text);
    JumpList.AddCustomCategories(_currentCategory);
    JumpList.Refresh();

    this.createCategoryItem.IsEnabled = true;
    this.createCategoryLink.IsEnabled = true;
    this.txtCategoryItem.IsEnabled = true;
    this.txtCategoryLink.IsEnabled = true;

_currentCategory = New JumpListCustomCategory(Me.txtCategory.Text)
JumpList.AddCustomCategories(_currentCategory)
JumpList.Refresh()

Me.createCategoryItem.IsEnabled = True
Me.createCategoryLink.IsEnabled = True
Me.txtCategoryItem.IsEnabled = True
Me.txtCategoryLink.IsEnabled = True

  1. Navigate to the createCategoryItem_Click method.
  2. In the method’s code, call the CheckFileName method and pass to it the Text property of the txtCategoryItem member variable. If the method returns false, return from this method without doing anything.
  3. Otherwise, create a new instance of the JumpListItem class and pass to its constructor the result of calling the GetTempFileName method with the txtCategoryItem.Text property. (The latter method creates a new temporary file with an appropriate file name.)
  4. Use the AddJumpListItems method of the _currentCategory member variable and pass to it the newly created JumpListItem instance.
  5. Call the JumpList.Refresh method to commit the changes to the jump list.
  6. The complete code should be similar to the following:if (!CheckFileName(txtCategoryItem.Text))
    return;

    JumpListItem jli = new JumpListItem(GetTempFileName(txtCategoryItem.Text));
    _currentCategory.AddJumpListItems(jli);
    JumpList.Refresh();

If Not CheckFileName(txtCategoryItem.Text) Then
Return
End If

Dim jli As New JumpListItem(GetTempFileName(txtCategoryItem.Text))
_currentCategory.AddJumpListItems(jli)
JumpList.Refresh()

  1. Navigate to the createCategoryLink_Click method.
  2. Repeat steps 27-31, but instead of using txtCategoryItem use txtCategoryLink and instead of using JumpListItem use JumpListLink. The JumpListLink constructor requires an additional title parameter—you should pass the txtCategoryLink.Text property for this parameter.

    The difference between shell items and shell links (represented as JumpListItem and JumpListLink in the managed wrapper, and by IShellItem and IShellLink in the underlying COM Shell APIs) is that a shell item contains only a path to a document that your application is registered to handle, but a shell link contains additional information and serves as a shortcut, including the application to launch, command-line arguments to pass to that application, a shortcut icon and other properties.

  3. The complete code should be similar to the following:if (!CheckFileName(txtCategoryItem.Text))
    return;

    JumpListLink jli = new JumpListLink( GetTempFileName(txtCategoryLink.Text), txtCategoryLink.Text);
    _currentCategory.AddJumpListItems(jli);
    JumpList.Refresh();

If Not CheckFileName(txtCategoryItem.Text) Then
Return
End If

Dim jli As New JumpListLink(GetTempFileName(txtCategoryLink.Text), _ txtCategoryLink.Text)
_currentCategory.AddJumpListItems(jli)
JumpList.Refresh()

  1. Compile and run the application.
  2. Navigate to the Jump List tab and click the ‘Ensure type registration’ button. The application will register the .png file association with itself in the Windows Registry. This may cause a User Account Control consent prompt—confirm the action if prompted.
  3. Check the ‘Show recent category’ checkbox and click the button above it. In the common file dialog, select a PNG file. Ensure that the application’s jump list now contains the selected PNG file in the Recent category.
  4. Click the ‘Add Tasks’ button and ensure that the jump list now contains links to Notepad, Calculator and Paint (and that there is a separator between the first two and the last one).
  5. Enter ‘Important’ in the category name textbox and click the ‘Create’ button.
  6. Enter ‘Activity report’ in the item textbox and click the ‘Add ShellItem’ button. Ensure that the jump list now contains a category called ‘Important’ with a single item called ‘Activity report’. For example:

    Figure 13

    The application’s jump list shows user tasks, the ‘Recent’ system category and the ‘Important’ custom category