Click here to Skip to main content
15,881,173 members
Articles / Desktop Programming / WPF

Using the new Windows 7 features for an iTunes Taskbar application

Rate me:
Please Sign up or sign in to vote.
4.95/5 (19 votes)
3 Feb 2010CPOL14 min read 43.9K   772   23   4
Demonstrates WPF C# examples of Windows Touch, Thumbnails, Task Dialogs, Thumbnail Toolbars, Overlay Icons, and Progress bars using the .NET Framework 3.51.

itunestaskbar1_-_toolbar_buttons.png

Introduction

The .NET 4 Framework and Visual Studio 2010 will have support for the new Windows 7 features like Taskbars and Multi-Touch. If you are using Visual Studio 2008 and the .NET 3.5 Framework, these new features are not natively supported, but you can still use these features by including some external assemblies.

This article will demonstrate these new Windows 7 features in an iTunes Taskbar application. It will also show some of the difficulties that you can come across when integrating these features into an application, and how to resolve the problems, like what happens when you add a Thumbnail Preview and your Thumbnail Toolbars disappear, or how to get Task Dialogs to appear in your application without receiving a NotSupportedException.

By the way, this has nothing to do with an IPad!! :)

Background

This application is not a replacement for iTunes, and cannot be run independently of iTunes. You do not need to have iTunes running before this application starts, because iTunes will automatically start when you instantiate the iTunes COM control, if it is not running already. There is currently no way to get around this.

iTunes does support some of the new Windows 7 features like Thumbnail Tooltips and Toolbars, but does not seem to have any other features. I wanted to integrate more Windows 7 features to make it more visual. This is what the current iTunes looks like if you hover over the icon on the taskbar:

itunestaskbar_-_itunes.png

You can also put iTunes in Toolbar mode to have easy access to the control buttons, but I don't think it's very impressive.

itunestaskbar_-_itunes_toolbar.png

Integrating iTunes COM

You can download the iTunes COM for Windows SDK to get more information on how to use the different interfaces of the iTunes SDK, and it provides some information on using the iTunes COM control with C#. However, it is not necessary to download it if you are using .NET.

To add the iTunes COM control, in Solution Explorer, right click on the References folder and select "Add Reference". Select the COM tab and find the iTunes Type Library (currently, it is "iTunes 1.12 Type Library"), and click "OK".

iTunesTaskbar

After you add the iTunes COM control, you should see iTunesLib appear in your References folder:

itunestaskbar_com_added.png

Once I added the reference to iTunesLib, I created a class called WrapperITunes in the iTunes namespace to handle all of the application's COM communication with iTunes.

The WrapperITunes class contains five methods:

  • Play() - Plays the current track.
  • Pause() - Pauses the current track.
  • Rewind() - Rewinds the current track. Sets to the beginning of the track. If less than 3 seconds into the track, goes to the previous track.
  • PreviousTrack() - Goes to the previous track.
  • NextTrack() - Goes to the next track.

It also contains three properties:

  • bool IsPlaying {get;} - Returns if a track is currently playing.
  • int PlayerPosition{get;set;} - Returns the position of the current track.
  • iTunesTrack CurrentTrack {get;} - Returns the current track, or null if no current track.

and four events:

  • PlayerPlayNotification - Notifies when iTunes has started playing.
  • PlayerStopNotification - Notifies when iTunes has stopped playing.
  • PlayerTrackChangedNotification - Notifies when the track has changed.
  • PlayerQuittingNotification - Notifies when iTunes is quitting.

These methods and properties are called from the NowPlaying class, and all of these events are handled in this class too.

Multi-Touch

The .NET 3.5 Framework does not directly support Multi-Touch, but it will be part of .NET 4. There is a way to integrate Multi-Touch support in your .NET 3.5 project. You can download the Windows 7 Multitouch .NET Interop Sample Library from Windows Touch: Developer Resources.

I only included the compiled assemblies Windows7.Multitouch.dll and Windows7.Multitouch.WPF.dll in this project, from the sample library. You can either add these compiled assemblies to your project, or you can download the sample and add the Wrapper\Windows7.Multitouch and Wrapper\Windows7.Multitouch.WPF projects to your solution after you agree to the EULA. If you are using WinForms rather than WPF, add the Wrapper\Windows7.Multitouch.WinForms project to your solution.

These libraries do not really give you all of the Multi-Touch management features that .NET 4 will, but they give you the raw touch messages as stylus events. The sample also provides touch manager examples for WPF, WinForms, and Win32, but I will demonstrate how to manage these events to support multi-touch using my own simpler manager. Their manager has many more features like dealing with multiple objects and inertia, so if you are looking for those features, check out their samples.

In the application, I added references to the Windows7.Multitouch.dll and Windows7.Multitouch.WPF.dll assemblies to the project. You could also add these projects from the sample library, and add references to these projects in your own application.

To initialize the touch events, check to see if the system is touch capable, then call Factory.EnableStylusEvents once. I call it in my Main window's Loaded event:

C#
//
// Enable Stylus if capable
//
if (TouchHandler.DigitizerCapabilities.IsMultiTouchReady)
{
    Factory.EnableStylusEvents(this);
}

You might be wondering why they just don't convert the touch events to mouse events. Well, the big difference between stylus events and mouse events is that the stylus events also contain a device ID. These device IDs allow us to track and differentiate different touch points. Here is an example of the stylus messages that you receive with multi-touch:

StylusMove ID:3 Location:118,239
StylusMove ID:2 Location:316,228
StylusMove ID:3 Location:118,239
StylusMove ID:2 Location:316,229
StylusMove ID:3 Location:118,239
StylusMove ID:2 Location:316,229
StylusMove ID:3 Location:118,240
StylusMove ID:2 Location:316,229
StylusMove ID:3 Location:118,239
StylusMove ID:2 Location:316,229
StylusMove ID:3 Location:119,239
StylusMove ID:3 Location:119,238
StylusMove ID:3 Location:125,232
StylusMove ID:3 Location:126,232

As you can see, the messages are coming from two IDs: 2 and 3, and they are kind of scattered. I needed to provide a better way to manage the events, so I created a class called MultiTouchManager that manages the stylus events and will fire events for single touch swiping left/right and multi-touch zoom.

There are three functions in MultiTouchManager that you simply redirect the stylus events to. They are explained in greater detail below:

C#
public void StylusDown(StylusDownEventArgs e)
public void StylusMove(StylusEventArgs e)
public void StylusUp(StylusEventArgs e)

and there are four events that the MultiTouchManager will fire:

  • OnStartGesture - Fires when the first touch event occurs.
  • OnEndGesture - Fires when the touch events have finished.
  • OnZoom - Fires when a multi-touch event is occurring.
  • OnFlick - Fires when a touch event has moved to the left or right 50 pixels.

StylusDown

StylusDown will add the new touch item to the touch list, then it will fire an OnStartGesture event if it's the only touch item, or it will record the starting distance if it is multi-touch. This will be used to calculate the zoom for future events:

C#
/// <summary>
/// Handler for the Stylus Down Event
/// </summary>
/// <param name="e"></param>
public void StylusDown(StylusDownEventArgs e)
{
    TouchItem touchItem = GetTouchItem(e.StylusDevice.Id);
    if (touchItem == null)
    {
        //
        // The touch item does not exist,
        // this is usually what happens
        //
        _touchList.Add(new TouchItem(e.StylusDevice.Id, 
                                     e.GetPosition(_element)));
    }
    else
    {
        //
        // The touch item already exists, this could
        // happen if we missed the Stylus up event,
        // like if we went outside the app before we lifted up.
        //
        touchItem.StartingPoint = 
          touchItem.LastPoint = e.GetPosition(_element);
    }
    if (_touchList.Count == 1)
    {
        if (OnStartGesture != null)
        {
            OnStartGesture(this, new EventArgs());
        }
    }
    else if (_touchList.Count == 2)
    {
        _startingDistance = GetCurrentDistance();
    }
}

StylusMove

StylusMove will get the TouchItem object from the device ID. I had to do a couple things with this event for multi-touch because the OS was firing off so many StylusMove events that the resizing of the window could not keep up with all the messages. So, the first thing I did was check if the LastPoint property was different from the current point. Sometimes I was getting 4 or 5 StylusMove events from the same device ID that had the exact same point. This helped a little, but I was still getting way more events than the sizing could keep up with. So, the next thing I did was add a DispatchTimer called _delayTimer. The purpose of this is when I get the first StylusMove event with two TouchItems, I record the distance between the two, and start the DispatchTimer which will fire off in 1/8th of a second. I keep on receiving StylusMove events until the DispatchTimer sends the timer tick, then I fire the OnZoom event with the last distance between the two points. That helped significantly, and allowed the sizing of the window to keep up with the multi-touch events.

If the StylusMove event occurs with only one TouchItem, I assume that the user is doing a single finger drag to the left or right. I compare the current touch location to the starting location and see if it is more than 50 pixels to the left or right. If it is, then I fire an OnEnd event and then an OnEndEventArg:

C#
/// <summary>
/// Handler for the Stylus Move Event
/// </summary>
/// <param name="e"></param>
public void StylusMove(StylusEventArgs e)
{
    TouchItem touch = GetTouchItem(e.StylusDevice.Id);
    if (touch != null)
    {
        Point currentPosition = e.GetPosition(_element);
        if (currentPosition == touch.LastPoint)
        {
            return;
        }

        touch.LastPoint = currentPosition;

        if (_touchList.Count == 1)
        {
            if (OnFlick != null)
            {
                double diffX = touch.LastPoint.X - touch.StartingPoint.X;
                if ((diffX < -50) || (diffX > 50))
                {
                    OnFlick(this, new TouchFlickEventArgs(
                        (diffX < -50) ? FlickDirection.Left : 
                         FlickDirection.Right));
                    _touchList.Remove(touch);
                    if (OnEndGesture != null)
                    {
                        OnEndGesture(this, new EventArgs());
                    }
                }
            }
        }
        else if (_touchList.Count == 2)
        {
                _difference = GetCurrentDistance() - _startingDistance;

            //
            // Set the timer if it is not running already
            //
            if (!_delayTimer.IsEnabled)
            {
                _delayTimer.Start();
            }
        }
    }
}

StylusUp

StylusUp will remove the TouchItem from the list. If there are any other TouchItems in the list, it will set their StartingPoint property to the value of the LastPoint property in case another TouchItem is created. If there are no more TouchItems, the manager will file an OnEndGesture event.

C#
/// <summary>
/// Handler for the Stylus Up Event
/// </summary>
/// <param name="e"></param>
public void StylusUp(StylusEventArgs e)
{
    if (RemoveTouchItem(e.StylusDevice.Id))
    {
        //
        // Set all remaining TouchItem object's starting points to their 
        // last point
        //
        if (_touchList.Count > 0)
        {
            foreach (var item in _touchList)
            {
                item.StartingPoint = item.LastPoint;
            }
        }
        else
        {
            if (OnEndGesture != null)
            {
                OnEndGesture(this, new EventArgs());
            }
        }
    }
}

Handling Touch Events in the Application

I handle the touch events in the NowPlaying class. I wanted this app to be compatible with applications that did not support multi-touch, so I only initialize these features if a multi-touch device is detected. The first thing I do is register for the stylus events, but these will actually be the multi-touch events. The second thing I do is initialize MultiTouchManager and register for its notification events.

C#
public NowPlaying()
{
    .
    .
    .
    if (Handler.DigitizerCapabilities.IsMultiTouchReady)
    {
        // If touch enabled, register for stylus events
        StylusDown += NowPlayingStylusDown;
        StylusUp += NowPlayingStylusUp;
        StylusMove += NowPlayingStylusMove;

        _multiTouchManager = new MultiTouchManager(this);
        _multiTouchManager.OnStartGesture += 
                           MultiTouchManagerOnStartGesture;
        _multiTouchManager.OnZoom += MultiTouchManagerOnZoom;
        _multiTouchManager.OnFlick += MultiTouchManagerOnFlick;
    }
    .
    .
    .
}

The next thing I do is redirect the stylus events to the MultiTouchManager.

C#
/// <summary>
/// Stylus Down Event Handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingStylusDown(object sender, StylusDownEventArgs e)
{
    .
    .
    .
    //
    // Pass event to the Multi-Touch Manager
    //
    _multiTouchManager.StylusDown(e);
}

/// <summary>
/// Stylus Up Event Handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingStylusUp(object sender, StylusEventArgs e)
{
    //
    // Pass event to the Multi-Touch Manager
    //
    _multiTouchManager.StylusUp(e);
}

/// <summary>
/// Stylus Move Event Handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingStylusMove(object sender, StylusEventArgs e)
{
    //
    // Pass event to the Multi-Touch Manager
    //
    _multiTouchManager.StylusMove(e);
}

Once the Multi-Touch Manager receives those messages, I wait for it to fire events for starting gesture, zooming, or flick events.

Multi-Touch Zooming

When I receive the OnStartGesture event in NowPlaying, I get the current Height and Width of the window.

itunestaskbar_-_touch_small.png

C#
/// <summary>
/// Handler for the MultiTouchManager's OnStartGesture Event 
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void MultiTouchManagerOnStartGesture(object sender, EventArgs e)
{
    _startingWidth = Width;
    _startingHeight = Height;
}

When I receive an OnZoom event from the Multi-Touch Manager, I just resize the window using the original height and width of the window and add the Difference value supplied by TouchZoomEventArgs. This method of adding the difference to the width and height works perfectly for this application because the album cover graphic is perfectly square. If you were to use this on a rectangle picture that was horizontal or vertical, you would need to calculate the aspect ratio. You can see from the screenshot below that the size of the player increases in size when you zoom with your fingers.

itunestaskbar_-_touch_large.png

C#
/// <summary>
/// Handler for the MultiTouchManager's OnZoom Event 
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void MultiTouchManagerOnZoom(object sender, TouchZoomEventArgs e)
{
    Width = _startingWidth + e.Difference;
    Height = _startingHeight + e.Difference;
}

Flicks

I also support left and right flicks for both mouse and touch. If you slide your finger to the left or right on the album cover, it will go to the previous or next track:

C#
/// <summary>
/// Handler for the MultiTouchManager's OnFlick Event 
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void MultiTouchManagerOnFlick(object sender, TouchFlickEventArgs e)
{
    if (e.FlickDirection == FlickDirection.Left)
    {
        PreviousTrack();
    }
    else if (e.FlickDirection == FlickDirection.Right)
    {
        NextTrack();
    }
}

New Windows 7 Taskbar Features

The New Windows 7 Taskbar features require that you download the Windows® API Code Pack for Microsoft® .NET Framework. In the Windows API Code Pack, there are five projects: Core, DirectX, ExtendedLinguisticServices, Sensors, and Shell. In this project, I use the Core and Shell projects. You can copy these projects to your solution and add the projects as references to your application. You can also just compile the Windows API Code Pack solution and then copy the assemblies to your project and then add the references to the assemblies.

Thumbnails

The Windows API Code Pack provides two ways to add a thumbnail preview to your application.

The first method is called the Live Thumbnail Preview method. It involves creating a TabbedThumbnail object and then calling the AddThumbnailPreview method:

C#
TabbedThumbnail preview = 
  new TabbedThumbnail(Application.Current.MainWindow, image, offset);
TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(preview);

The underlying Win32 API's AddThumbnailPreview method uses the RegisterTab, SetTabOrder, and SetTabActive methods in the ITaskbarList3 interface.

The second way is the Thumbnail Clips method using the SetThumbnailClip method:

C#
TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip(
               new WindowInteropHelper(this).Handle, rect);

SetThumbnailClip uses the SetThumbnailClip method from the ITaskbarList3 interface to set the dimensions around the part of the screen that you want to appear in the thumbnail.

Both of these methods have their own pros and cons.

AddThumbnailPreview

Pros
  • Adds a thumbnail title
  • Adds a thumbnail tooltip
  • Updates image when window is minimized
Cons
  • Causes the taskbar buttons to disappear (see below)

Note: The taskbar buttons seem to disappear when the ITaskbarList3::SetTabOrder method is called.

itunestaskbar1_-_no_toolbar_buttons.png

SetThumbnailClip

Pros
  • Doesn't cause the taskbar buttons to disappear
Cons
  • No thumbnail titles
  • No thumbnail tooltips
  • Does not update image when minimized or out of view in the window

The disappearance of the thumbnail toolbars using AddThumbnailPreview was too big of a con for me. The samples in the Windows 7 Training Kit for Developers do not allow us to use the AddThumbnailPreview method with the taskbar buttons. I modified the sample so I could see if the problem existed with that sample, and I verified that it did.

So, I would need to use the SetThumbnailClip method.

C#
/// <summary>
/// Update the Taskbar's thumbnail preview
/// </summary>
private void UpdateThumbnailPreviewLocation()
{
    //
    // Get the bounds of the AlbumCoverImage Control
    //
    GeneralTransform transform = 
      nowPlaying.AlbumCoverImage.TransformToAncestor(this);
    System.Windows.Point rootPoint = 
      transform.Transform(new System.Windows.Point(0, 0));
    int width = (int)nowPlaying.AlbumCoverImage.ActualWidth;
    int height = (int)nowPlaying.AlbumCoverImage.ActualHeight;

    //
    // Set the Thumbnail Image
    //
    TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip(
        new WindowInteropHelper(this).Handle,
        new Rectangle((int)rootPoint.X, (int)rootPoint.Y, width, height));
}

Adding Titles and Tooltips Using the Thumbnail Clips Method

Since none of the ITaskbarList interfaces has a method to set the thumbnail title, the thumbnail title gets its text from the window's title. So, if you change the window's title, the thumbnail title changes as well.

The ITaskbarList3 interface has a SetThumbnailTooltip method that allows you to set the tooltip text, but The Windows API Code Pack lacks the method that calls this interface's method. So, a simple fix for this is to find the TabbedThumbnailManager.cs file and add the following method to the TabbedThumbnailManager class:

C#
/// <summary>
/// Specifies or updates the text of the tooltip that
/// is displayed when the mouse pointer rests on an
/// individual preview thumbnail in a taskbar button flyout.
/// </summary>
/// <param name="windowHandle">The handle to the window
/// whose thumbnail displays the tooltip</param>
/// <param name="tooltip">The pointer to the text
/// to be displayed in the tooltip. This value can be 
/// NULL, in which case the title of the window specified
/// by hwnd is used as the tooltip.</param>
public void SetThumbnailTooltip(IntPtr windowHandle, string tooltip)
{
    TaskbarManager.Instance.TaskbarList.SetThumbnailTooltip(windowHandle, tooltip);
}

You are now able to semi-add titles and tooltips to your thumbnails.

itunestaskbar_-_title_or_tooltips.png

C#
/// <summary>
/// Handler for the OnUpdatePreview Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingOnUpdatePreview(object sender, UpdatePreviewEventArgs e)
{
    //
    // Update the title and the tooltip
    //
    Title = e.Artist;
    TaskbarManager.Instance.TabbedThumbnail.SetThumbnailTooltip(
        new WindowInteropHelper(this).Handle,
        e.Artist + "\nTrack: " + 
        e.TrackName + "\nAlbum: " + e.Album);

    //
    // Update the Taskbar's thumbnail preview
    //
    UpdateThumbnailPreviewLocation();
    .
    .
    .
}

The tooltips can be multi-line as well.

Thumbnail Toolbars

itunestaskbar_-_taskbar_buttons.png

Thumbnail toolbars are a new feature that allow you to add up to seven toolbar buttons underneath the preview. Toolbar buttons cannot be added or deleted; however, you can change icons and tooltip text to give an appearance of buttons changing.

I add the three buttons in MainWindow.xaml.cs:

C#
/// <summary>
/// Create the Thumbnail Toolbars
/// 
/// </summary>
private void CreateThumbnailToolbarButtons()
{
    _buttonBackward = new ThumbnailToolbarButton(
        iTunesTaskbar.Resources.Backward, "Previous");
    _buttonBackward.Click += (s, e) => nowPlaying.Rewind();

    _buttonPlay = new ThumbnailToolbarButton(
        iTunesTaskbar.Resources.Play, "Play");
    _buttonPlay.Click += (s, e) => nowPlaying.Play();

    _buttonNext = new ThumbnailToolbarButton(
        iTunesTaskbar.Resources.Forward, "Next");
    _buttonNext.Click += (s, e) => nowPlaying.NextTrack(); 

    TaskbarManager.Instance.ThumbnailToolbars.AddButtons(
        new WindowInteropHelper(this).Handle,
        _buttonBackward, _buttonPlay, _buttonNext);

    UpdateThumbnailToolbarButtons();
}

UpdateThumbnailToolbarButtons determines whether the Play or Pause icon and tooltip should be displayed. It is also called when we get the OnPlay and OnStop events from the player.

C#
private void UpdateThumbnailToolbarButtons()
{
    if (nowPlaying.IsTrackSelected)
    {
        _buttonPlay.Icon = nowPlaying.IsPlaying ? 
            iTunesTaskbar.Resources.Pause : 
            iTunesTaskbar.Resources.Play;
        _buttonPlay.Tooltip = 
          nowPlaying.IsPlaying ? "Pause" : "Play";

        _buttonPlay.Enabled = true;
        _buttonBackward.Enabled = true;
        _buttonNext.Enabled = true;
    }
    else
    {
        _buttonPlay.Enabled = false;
        _buttonBackward.Enabled = false;
        _buttonNext.Enabled = false;
    }
}

This is the Paused state of the player with the Play icon in the button showing:

itunestaskbar_-_taskbar_buttons_play.png

This is the Playing state of the player with the Pause icon in the button showing:

itunestaskbar_-_taskbar_buttons_pause.png

Task Dialogs

itunestaskbar_taskdialog.png

Windows Vista introduced the new enhanced dialog which offers many more features than a standard Message Box. I have added a couple, but I really am not taking advantage of all the features that they have to offer. What I really wanted to touch on was the problems that people have when trying to add this feature.

C#
using Microsoft.WindowsAPICodePack.Dialogs;

if (!nowPlaying.IsTrackSelected)
{
    TaskDialog taskDialog = new TaskDialog();
    taskDialog.Icon = TaskDialogStandardIcon.Information;
    taskDialog.Caption = "iTunes Taskbar";
    taskDialog.InstructionText = "There is no track playing in iTunes";
    taskDialog.Text = "Please go to iTunes " + 
                      "and select a playlist, then select a track";
    taskDialog.StandardButtons = TaskDialogStandardButtons.Ok;
    taskDialog.DetailsExpandedLabel = "Click for more details";
    taskDialog.DetailsExpandedText = "This is more detail";
    taskDialog.ExpansionMode = 
      TaskDialogExpandedDetailsLocation.ExpandFooter;

    taskDialog.Show();
}

When you first try to show a TaskDialog, you will most likely get a NotSupportedException that says "TaskDialog feature needs to load version 6 of comctl32.dll, but a different version is current loaded in memory".

itunestaskbar_vshostloaded_exception.png

The reason that this error is happening is because the underlying Win32 API used to show the dialog is a function called TaskDialogIndirect, and it is only available with version 6 of comctl32.dll and higher.

To load version 6 of comctl32.dll, you need to create a manifest with the name (appname).exe.manifest and add the following to the manifest's /assembly/dependency node:

XML
<dependentAssembly>
    <assemblyIdentity type="win32" 
      name="Microsoft.Windows.Common-Controls"
      version="6.0.0.0" 
      processorArchitecture="*" 
      publicKeyToken="6595b64144ccf1df"
      language="*" />
</dependentAssembly>

If you retry it after you add the manifest to the assembly, it will probably still not work. The reason is because Visual Studio has what is known as a hosting process that it uses to run your debugging sessions to improve performance. This process does not get unloaded when you stop your debugging session, and it already has comctl32.dll loaded. So, it does not reload the new comctl32.dll when you start the debug session again. The hosting process is named [appname].vshost.exe, so for iTunesTaskbar, it is named iTunesTaskbar.vshost.exe.

You can see here from the Process Monitor that iTunesTaskbar.vshost.exe is still loaded even when it is not being debugged, and the comctl32.dll version is 5.82.

itunestaskbar_vshostloaded_procexp.png

To fix this problem, update the manifest and then close Visual Studio, then restart it.

Just a note, even after you restart Visual Studio, this problem will still occasionally happen. If it does, then just restart Visual Studio and it should fix the problem. You can disable the hosting process, but this will also lead to slower performance while debugging.

Taskbar Overlay Icons

I use Taskbar Overlay Icons to give a very tiny view of the album cover for the track being played. I know it is very small, and in most cases, is only helpful if you are very familiar with the look of the album cover. I had a sample where I had it reversed, and changed the Icon to the album cover, and set the music note as the overlay icon, but it was blocking most of the progress bar. It can easily be changed for those who are interested in that behavior.

itunestaskbar_overlayicon.png

C#
/// <summary>
/// Handler for the OnUpdatePreview Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingOnUpdatePreview(object sender, UpdatePreviewEventArgs e)
{
    .
    .
    .
    //
    // Set the Taskbar's Overlay Icon
    //
    TaskbarManager.Instance.SetOverlayIcon(e.Icon, null);
    //Icon = icon;
}

Taskbar Progress Bars

itunestaskbar_normal_progress.png

I use the Taskbar Progress Bar to show the progress of the current track being played. When the NowPlaying control fires an OnProgressChanged event, the MainWindow receives the event and updates the progress bar:

C#
/// <summary>
/// Handler for the OnProgressChanged Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingOnProgressChanged(object sender, TrackProgressEventArgs eventArgs)
{
    //
    // Update Taskbar Progress
    //
    TaskbarManager.Instance.SetProgressValue(
      eventArgs.CurrentPosition, eventArgs.MaximumPosition);
}

Furthermore, you can visually show the active state of a progress bar by the color of the progress bar. The normal state is green, and I display normal when iTunes is currently playing a track.

C#
/// <summary>
/// Handler for the OnPlay Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingOnPlay(object sender, EventArgs e)
{
    //
    // Set the progress state to normal
    //
    TaskbarManager.Instance.SetProgressState(
                   TaskbarProgressBarState.Normal);
    .
    .
    .
}

When the track is paused, I show it in a paused state, which is yellow:

itunestaskbar_paused_progress.png

C#
/// <summary>
/// Handler for the OnStop Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void NowPlayingOnStop(object sender, EventArgs e)
{
    //
    // Set the progress state to paused
    //
    TaskbarManager.Instance.SetProgressState(
                   TaskbarProgressBarState.Paused);
    .
    .
    .
}

History

  • Feb. 3, 2010: Initial version of the article.

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)
United States United States
Thank you for voting on my articles!

MCSD.NET in C#


Comments and Discussions

 
GeneralExcellent article... Pin
Fabrice Vergnenegre13-Feb-10 9:05
Fabrice Vergnenegre13-Feb-10 9:05 
GeneralRe: Excellent article... Pin
Eric Haddan15-Feb-10 17:21
Eric Haddan15-Feb-10 17:21 
GeneralWow! Pin
dhuddleston4-Feb-10 2:37
dhuddleston4-Feb-10 2:37 
GeneralRe: Wow! Pin
Eric Haddan4-Feb-10 10:47
Eric Haddan4-Feb-10 10:47 

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.