Alessandro Del Sole's Blog

/* A programming space about Microsoft® .NET® */
posts - 159, comments - 0, trackbacks - 0

My Links

News

Your host

This is me! This space is about Microsoft® .NET® and Microsoft® Visual Basic development. Enjoy! :-)

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.

Microsoft MVP

My MVP Profile

I'm a VB!

Watch my interview in Seattle

My new book on VB 2015!

Pre-order VB 2015 Unleashed Pre-order my new book "Visual Basic 2015 Unleashed". Click for more info!

My new book on LightSwitch!

Visual Studio LightSwitch Unleashed My book "Visual Studio LightSwitch Unleashed" is available. Click the cover!

Your visits

Follow me on Twitter!

CodePlex download Download my open-source projects from CodePlex!

Article Categories

Archives

Post Categories

.NET Framework

Blogroll

Help Authoring

Microsoft & MSDN

Setup & Deployment

Visual Basic 2005/2008/2010

Windows 7 & WPF 4: adding buttons onto task bar icons

Windows Presentation Foundation 4, the new version currently available in Beta 2 which will be part of .NET Framework 4/VS 2010, offers native integration with Windows 7 without the need of utilizing external components and libraries (at least for most activities). Among available functionalities, multi-touch and task bar integration are the most important.

In this post I'm going to discuss how you can add buttons to the application's icon in the Windows task bar, very similarly to what you can see by running Windows Media Player, which provides button for controlling the media being played, available when the mouse pointer passes over the application icon:

The goal of this post is building, although with limited capabilities, a media player with WPF 4 and Visual Basic 2010. Next we will add three buttons that will be visible in the task bar. After creating the project, let's start by defining the user interface as follows:

<Window x:Class="MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="MainWindow" Height="350" Width="540">

   

    <!--A simple gradient background -->

    <Window.Background>

        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

            <GradientStop Color="Black" Offset="0" />

            <GradientStop Color="White" Offset="1" />

        </LinearGradientBrush>

    </Window.Background>

    

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition />

            <RowDefinition Height="50" />

        </Grid.RowDefinitions>

 

        <!-- The MediaElement is placed in the first row (notice

             how the volume is set via data-binding)-->

        <MediaElement Name="Media1" Grid.Row="0" LoadedBehavior="Manual"

                      Volume="{Binding ElementName=VolumeSlider, Path=Value}"

                      MediaFailed="Media1_MediaFailed" >

        </MediaElement>

So we will have some buttons, both on the window and on the task bar. This means that we will have duplicate buttons although in differente places. A good approach is implementing the WPF commanding technique instead of handling Click events. Basically we use some commands that are assigned to controls and that will be executed only when the specified conditions are true. Before going into that, let's complete the code for the Window:

        <!-- Some buttons. Notice how predefined commands are assigned to the Command property -->

        <StackPanel Orientation="Horizontal" Grid.Row="1">

            <Button Name="PlayButton" Width="70" Height="40" Command="MediaCommands.Play"

                    Margin="5" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" />

           

            <Button Name="PauseButton" Width="70" Height="40" Command="MediaCommands.Pause"

                    Margin="5"

                    Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>

           

            <Button Name="StopButton" Width="70" Height="40"

                    Margin="5" Command="MediaCommands.Stop"

                    Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>

           

            <Button Name="BrowseButton" Width="40" Height="40"

                    Margin="5" Content="..."/>

            <!-- Setting the volume -->

            <Slider Name="VolumeSlider" Width="80" Margin="5"

                    Minimum="0" Maximum="1" Value="0.5" TickFrequency="0.1"

                    AutoToolTipPlacement="TopLeft" TickPlacement="BottomRight"/>

           

        </StackPanel>

    </Grid>

As you may know, WPF defines some default commands which target different scenarios, so that you do not need to implement custom ones. MediaCommands expose a number of commands that can be used in multimedia situations like this one. So the control's Command property is assigned with the desired command. Since commands also define a localizable text to be shown inside the control, the Content property is bound to the Text property of the command, which returns the localized text. If you run the English version of Windows like me, the localized text will be anyway Play, Stop, Pause. Now let's define the CommandBindings, in order to declare the event handlers that will be executed with regard of commands:

    <!-- Assigning event handlers to commands-->

    <Window.CommandBindings>

        <CommandBinding Command="MediaCommands.Play" x:Name="PlayCommand"

                        Executed="PlayCommand_Executed"

                        CanExecute="PlayCommand_CanExecute"/>

        <CommandBinding Command="MediaCommands.Stop" x:Name="StopCommand"

                        Executed="StopCommand_Executed"

                        CanExecute="StopCommand_CanExecute"/>

        <CommandBinding Command="MediaCommands.Pause" x:Name="PauseCommand"

                        Executed="PauseCommand_Executed"

                        CanExecute="PauseCommand_CanExecute"/>

    </Window.CommandBindings>

 

Each CommandBinding establishes that the Executed event handler will run the specified action while CanExecute will check if such action is actually executable. This also requires some Visual Basic code that I will show later. Now we can write code for integrating with Windows 7. Look at this:

    <Window.TaskbarItemInfo>

        <TaskbarItemInfo Description="Control your media" ThumbnailClipMargin="5">

            <TaskbarItemInfo.ThumbButtonInfos>

                <ThumbButtonInfoCollection>

                    <ThumbButtonInfo x:Name="ThumbPlayButton" Command="MediaCommands.Play"

                                 DismissWhenClicked="False" CommandTarget="{Binding ElementName=PlayButton}"

                                 Description="Play" ImageSource="/MediaPlayer;component/Images/PlayHS.png" />

                   

                    <ThumbButtonInfo x:Name="ThumbStopButton" Command="MediaCommands.Stop"

                                 DismissWhenClicked="False" CommandTarget="{Binding ElementName=StopButton}"

                                 Description="Stop" ImageSource="/MediaPlayer;component/Images/StopHS.png" />

 

                    <ThumbButtonInfo x:Name="ThumbPauseInfo" Command="MediaCommands.Pause"

                                 DismissWhenClicked="False" CommandTarget="{Binding ElementName=PauseButton}"

                                 Description="Pause" ImageSource="/MediaPlayer;component/Images/PauseHS.png" />

 

                </ThumbButtonInfoCollection>

            </TaskbarItemInfo.ThumbButtonInfos>

        </TaskbarItemInfo>

    </Window.TaskbarItemInfo>

</Window>

The TaskbarItemInfo object gets a reference to the application icon in the task bar. The Description property will show a tooltip when the mouse pointer passes, while ThumbnailClipMargin allows setting a margin. Among the elements that it can store, there are buttons. They are represented by ThumButtonInfo objects (max number is 7) which are contained inside a collection named ThumButtonInfoCollection. Each task bar button works basically like a normal Button control, since it expose a Click event and a Command, which can be assigned with the appropriate command defined in XAML code and that we previously assigned to normal buttons too. Notice that these particular buttons do not show text, because they can just show images so you have to assign the ImageSource property. Remember that such images must be 16 x 16. DismissWhenClicked is used to specify that a button is not available only once. Also notice how the CommandTarget property binds the current button to the related normal one on the window. Now let's switch to the Visual Basic code and write the following: colleghi l'attuale pulsante al corrispondente fratello maggiore sulla finestra. Ora si passa al codice Visual Basic.

Class MainWindow

 

    Private sourceMedia As String = String.Empty

 

    Private Sub BrowseButton_Click(ByVal sender As System.Object,

                                   ByVal e As System.Windows.RoutedEventArgs) Handles BrowseButton.Click

 

        Dim dialog As New Microsoft.Win32.OpenFileDialog

        With dialog

            .Title = "Select a media file"

            .Filter = "Avi & Wmv|*.avi;*.wmv|All files|*.*"

 

            If .ShowDialog = True Then

                Me.sourceMedia = .FileName

                Me.Media1.Source = New Uri(sourceMedia, UriKind.RelativeOrAbsolute)

            End If

        End With

    End Sub

 

 

    'In case opening the media file fails

    Private Sub Media1_MediaFailed(ByVal sender As System.Object,

                                   ByVal e As System.Windows.ExceptionRoutedEventArgs)

        MessageBox.Show(e.ErrorException.Message)

    End Sub

 

    'Executing command actions

    Private Sub PlayCommand_Executed(ByVal sender As System.Object,

                                     ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        Me.Media1.Play()

    End Sub

 

    Private Sub StopCommand_Executed(ByVal sender As System.Object,

                                     ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        Me.Media1.Stop()

    End Sub

 

    Private Sub PauseCommand_Executed(ByVal sender As System.Object,

                                      ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        Me.Media1.Pause()

    End Sub

 

    'Setting the condition tha makes commands executable

    'if verified as true

    Private Sub PlayCommand_CanExecute(ByVal sender As System.Object,

                                       ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

        e.CanExecute = Me.Media1.Source IsNot Nothing

    End Sub

 

    Private Sub StopCommand_CanExecute(ByVal sender As System.Object,

                                       ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

        e.CanExecute = Me.Media1.Source IsNot Nothing

    End Sub

 

    Private Sub PauseCommand_CanExecute(ByVal sender As System.Object,

                                        ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

        e.CanExecute = Me.Media1.Source IsNot Nothing

    End Sub

End Class

Simply notice how the CanExecute handlers set a condition that will disable controls on the UI unless it is false. Such condition will become True only when you select a media file (and thus controls will be automatically enabled). Now we can run the application and enjoy the magic:

By writing the above code we made our application icon interactive, adding buttons that allow us controlling how the media file is played. This is a very cool feature of WPF 4 for Windows 7.

You can download the code for this blog post from the following address of the MSDN Code Gallery.

Alessandro

Print | posted on domenica 24 gennaio 2010 13:17 | Filed Under [ Visual Studio 2010 Visual Basic Windows Presentation Foundation ]

Feedback

No comments posted yet.

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 7 and 3 and type the answer here:

Powered by:
Powered By Subtext Powered By ASP.NET