lundi 7 décembre 2015

Re-purposing Media Player Framework (3.0.0.1) buttons to do something else (XAML,C#)


In this small example I will explain why I re-purposed some media player buttons on my MediaPlayer.  At first I was looking into creating a whole new button and linking it with events using MVVM with a RelayCommand, I wanted to do this well of course.

To start I wanted to create my own button from scratch and bind it with an event, this quickly became difficult as I am not a great designer (looking at my apps you will quickly understand what I mean) and binding an event on events that are that deep (in a ControlTemplate) is not always the best idea or the easiest.  It does work and it is doable, however I was sometimes getting some issues on the tapped event which was not being fired (probably the tapped event was getting caught by some other button in the player).

So I started looking at my XAML code to see what I could do:

  <playerFramework:MediaPlayer
                x:Name="Player"
                Background="Transparent"
                IsPlayPauseVisible="True"
                Opacity="1"       
                />       

The C# code for my player looked as follow:

                    Player.Source = MySource;
                    Player.MediaOpened += Player_OnMediaOpened;
                    Player.MediaClosed += Player_MediaClosed;
                    Player.Play();

and then it hit me! why dont I just re-use some of the buttons on the player that I am not using.  This would allow my to not have to re code all of the different events linked to the button and also have the effects already coded for me like the on press event and mouse over events and more.

 In my example I decided to re purpose the full screen button to start,  all we need to do on the MediaPlayer is to show the FullScreenButton:

  <playerFramework:MediaPlayer
                x:Name="Player"
                VerticalAlignment="Bottom"
                HorizontalAlignment="Left"
                Background="Transparent"
                IsFullScreenEnabled="True"    <- this
                IsFullScreenVisible="True"    <- this
                IsPlayPauseVisible="True"
                Opacity="1"       
                />       



Then we just need to catch the isFullScreenChanged event like this:

        
private void InitPlayer()
{
        Player.Source = MySource;
        Player.MediaOpened += Player_OnMediaOpened;
        Player.MediaClosed += Player_MediaClosed;
        Player.IsFullScreenChanged += Player_IsFullScreenChanged;
        Player.Play();
}



 private void Player_IsFullScreenChanged(object sender, RoutedPropertyChangedEventArgs<bool> e)
        {
            //do what ever you want to do...
        }


And now you can do whatever you wish when the full screen button is clicked on the player.

Next we will edit the AppBarButton style so that we show our custom button, like I have written in previous articles you need to get the default style of the AppBarButton and edit it as you need. For this example we will just edit the element <Viewbox> comment its Ellipse and ContentPresenter and add an image:

    <Style x:Key="PlayerAppBarCloseButtonStyle" TargetType="AppBarButton">
        <!--<Setter Property="Foreground" Value="{ThemeResource AppBarItemForegroundThemeBrush}"/>-->
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="IsCompact" Value="True" />
        <Setter Property="Height" Value="40" />
        <Setter Property="Width" Value="40" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="AppBarButton">
                    <Grid x:Name="RootGrid" Background="Transparent">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="ApplicationViewStates">
                                <VisualState x:Name="FullSize" />
                                <VisualState x:Name="Compact" />
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="PointerOver" />
                                <VisualState x:Name="Pressed" />
                                <VisualState x:Name="Disabled" />
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused" />
                                <VisualState x:Name="Unfocused" />
                                <VisualState x:Name="PointerFocused" />
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Viewbox Margin="{TemplateBinding Padding}">
                            <Grid Width="45" Height="45">
                                <Ellipse x:Name="BackgroundEllipse"
                                         Width="45"
                                         Height="45"
                                         Fill="#BBFFFFFF"
                                         UseLayoutRounding="False" />

                                <!--<Ellipse x:Name="BackgroundEllipse" Fill="{ThemeResource AppBarItemBackgroundThemeBrush}" UseLayoutRounding="False"/>-->
                                <!--<Ellipse x:Name="OutlineEllipse" Stroke="{ThemeResource AppBarItemForegroundThemeBrush}" StrokeThickness="2" UseLayoutRounding="False"/>-->
                                <!--<ContentPresenter x:Name="Content" AutomationProperties.AccessibilityView="Raw" Content="{TemplateBinding Icon}" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"
                                                  Height="45"
                                                  Width="45"
                                  Opacity="1"
                                                  />-->
                                <Image Width="25"
                                       Height="25"
                                       Margin="10"
                                       Source="/Assets/VideoPage/close.png" />

                            </Grid>
                        </Viewbox>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Lastly we just need to link this style to our FullScreenButton which should be located in your ControlTemplate of the video media element as follow:


 <AppBarButton x:Name="FullScreenButton"
               Width="45"
               Height="45"
               Margin="8,0,8,0"
               Style="{StaticResource PlayerAppBarCloseButtonStyle}"               Visibility="{Binding IsFullScreenButtonVisible,
                            Converter={StaticResource VisibleIfConverter},
                              RelativeSource={RelativeSource Mode=TemplatedParent}}">
                      <local:MediaControls.Behavior>
                          <local:FullScreenButtonBehavior ViewModel="{Binding ViewModel, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
                      </local:MediaControls.Behavior>
 </AppBarButton>

And there you have it, you have re purposed an AppBarButton to do what you need it to do.  I used the FullScreenButton but you could have used any other button that you are not using as long as it has a Changed event linked to it!

Happy coding.

As a great philosopher once said "Rien ne se perd, rien ne se crée, tout se transforme."  Antoine Lavoisier