Click here to Skip to main content
5,788,212 members and growing! (19,720 online)
Email Password   helpLost your password?
Web Development » Silverlight » Controls     Beginner License: The Microsoft Public License (Ms-PL)

A Silverlight Video Player Carousel Control

By cokkiy

VideoCarousel is a Silverlight V2 control can play media in an interactive carousel.
C# (C# 3.0, C# 2.0, C#), .NET (.NET, .NET 3.0, .NET 2.0), Silverlight, Dev, Design

Posted: 26 Nov 2008
Updated: 26 Nov 2008
Views: 4,981
Bookmarked: 22 times
Note: This is an unedited reader contribution
Announcements
Loading...



Search    
Advanced Search
Sitemap
7 votes for this Article.
Popularity: 2.98 Rating: 3.53 out of 5
1 vote, 14.3%
1
0 votes, 0.0%
2
2 votes, 28.6%
3
0 votes, 0.0%
4
4 votes, 57.1%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Screen Capture 1

Introduction

Few days ago I have been post an article about how creating a Silverlight Carousel control, you can read here. In this article I'll creating a new Carousel which can be used to playing video or audio. I named it VideoCarousel. The VideoCarousel very similar to the Carousel except it can play video or audio. If you have been try the Carousel control, maybe you already know the Carousel has a Panel display the user selected picture (with title). In the VideoCarousel the Panel replaced by a video player control. If you want to know how the Carousel working, you may need to read this article.

You may use the VideoCarousel control as a video player in your web page. It's support dynamic add/ remove media (video or audio) info to it's collection. The media info can include a picture (you can capture a frame from the film), a Uri where the media located, a title, the name of the director, the name of the main actors and the name of the producer.

When the user move the Mouse over the CarouselItem, the media info will be appear. When the user select the CarouselItem, the select video picture will be appear in the selected item panel and the media will be auto buffer. If the media ready, user can play it or if you set the AutoPlay property to true, the media will be auto play. The Carousel menu auto disappear when the media palying.

Display media info when mouse over:

Display media info when mouse over

The carousel hide when video playing:

The carousel hide when video playing

Background

You already know I have been create a Silverlight V2 control named Carousel which can display a collection of picture in an interactive carousel. I like the control so I made some upgrade for it, now it can use as a video player.

Key Features

  • Silverlight V2 control, all written by C#.
  • Very easy to use.
  • Auto display a loading animation when the media downloading.
  • Can play video in full screen mode.
  • Has a very attracting carousel as video menu.

Using the Control

Using the VideoCarousel control is very simple. In your Silverlight application, add a reference of the assembly (the name of the assembly is Cokkiy.Display.VideoCarousel). Then in your page's XAML file, do like following:

In the beginning of the page, add a xmlns reference.

<UserControl x:Class="VideoCarouselTest.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:display="clr-namespace:Cokkiy.Display;assembly=Cokkiy.Display.VideoCarousel"
   >

Then, place the VideoCarousel control inside to your layout control, such as Grid or StackPanel:

<Grid x:Name="LayoutRoot" Background="White">        
        <display:VideoCarousel x:Name="carousel" TurnDirection="Counterclockwise" Padding="5,5,5,5" >

Also, you can set it's background like this:

 <display:VideoCarousel.Background>
          <LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">
              <GradientStop Color="#FF000000"/>
              <GradientStop Color="#FFFFFFFF" Offset="1"/>
           </LinearGradientBrush>
 </display:VideoCarousel.Background>

If you want set the media info static in your XAML file, you can do as following:

 <display:VideoCarousel.ItemSources>
    <display:ItemSource Title="Sample Video" Director="Unknown" Actors="Unknown" 
                  Producer="Microsoft" 
       ImageSource="Images/01.jpg" MediaSource="Videos/SampleVideo.wmv"/>
          <display:ItemSource Title="Sample" ImageSource="Images/02.jpg" 
                     MediaSource="Videos/Sample.wmv"/>
          <display:ItemSource Title="SL VC1 Video" ImageSource="Images/03.jpg" 
                    MediaSource="Videos/sl.wmv"/>
          <display:ItemSource Title="silverlight" ImageSource="Images/04.jpg" 
                     MediaSource="Videos/silverlight.wmv"/>
          <display:ItemSource Title="SampleVideo" ImageSource="Images/05.jpg" 
                       MediaSource="Videos/SampleVideo.wmv"/>
          <display:ItemSource Title="Sample" ImageSource="Images/06.jpg" 
                       MediaSource="Videos/Sample.wmv"/>
          <display:ItemSource Title="sl" ImageSource="Images/07.jpg" 
                       MediaSource="Videos/sl.wmv"/>
          <display:ItemSource Title="silverlight" ImageSource="Images/08.jpg" 
                      MediaSource="Videos/silverlight.wmv"/>
          <display:ItemSource Title="SampleVideo" ImageSource="Images/09.jpg" 
                      MediaSource="Videos/SampleVideo.wmv"/>
          <display:ItemSource Title="silverlight" ImageSource="Images/10.jpg" 
                       MediaSource="silverlight.wmv"/>
    <display:ItemSource Title="Error created" ImageSource="Images/11.jpg"/>
</display:VideoCarousel.ItemSources>

In the end, close the tag.

        </display:VideoCarousel>
</Grid>

But in most situation, you want dynamic add media info into the collection based on user selection or film just watched. You can subscribe the SelectedItemChanged or the CurrentMediaStateChnaged event.The SelectedItemChanged event occurs when user selected an item and the CurrentMediaStateChnaged event occurs when the media playing, paused or stoped. The following code add a film to the control.

 carousel.ItemSources.Add(
         new Uri("Images/25.jpg", UriKind.Relative), // a picture from the film
         new Uri("Videos/sl.wmv",UriKind.Relative), // the media Uri addresss
         "Dynamic added SL VC1 Video", // Film title
         "Jo Coco", // the director
         "Tom Crausel", // the main actor
         "the Disney Product"); // the producer
    

You also want remove the media the user just watched when the meida ended.

 void carousel_CurrentMediaStateChnaged(object sender, MediaStateChangedEventArgs e)
{
      if (e.MediaState == MediaState.Ended)
      {
          // remove the media user just watched
          carousel.ItemSources.Remove(e.Title);
      }
}

In some times, you may want the Carousel part not auto turnning. You can simple set the AutoTurn to false gets this effects. When the Carousel not auto turnning, a button will auto appear in each side of the Carousel, the user can use the buttons to turns left or right.

videoCarousel4.JPG

In XAML file you can do like this:

<display:VideoCarousel x:Name="carousel" AutoTurn="False" 
     TurnDirection="Counterclockwise" Padding="5,5,5,5" >

Or you can set it in code.

How It Works

In here I don't repeat how the Carousel works (you can read how it works here). The main point of here is the video player. The video player is a UserControl. Here is the XAML (note here I omits all the control template):

 <UserControl x:Class="Cokkiy.Display.VideoPlayer"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
  xmlns:mwc="clr-namespace:Microsoft.Windows.Controls;assembly=Cokkiy.Common.Controls"
  xmlns:cc="clr-namespace:Cokkiy.Common.Controls;assembly=Cokkiy.Common.Controls"
  xmlns:resources="clr-namespace:Cokkiy.Display.Resources"
  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
  >
  <Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
       MouseLeave="LayoutRoot_MouseLeave" MouseMove="LayoutRoot_MouseMove" 
           Opacity="1" Background="Transparent">
     <vsm:VisualStateManager.VisualStateGroups>
	<vsm:VisualStateGroup x:Name="PositionStates">
		<vsm:VisualState x:Name="SetPositionState">
                  <Storyboard>
    		    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    			        Duration="00:00:00.0010000" 
    				         Storyboard.TargetName="positionSlider" 
    				                Storyboard.TargetProperty="(UIElement.Opacity)">
    			<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    		    </DoubleAnimationUsingKeyFrames>
    		    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    			           Duration="00:00:00.0010000" 
    			             Storyboard.TargetName="_base" 
    			             Storyboard.TargetProperty="(UIElement.Opacity)">
    			 <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    		    </DoubleAnimationUsingKeyFrames>
    	            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    			         Duration="00:00:00.0010000" 
    			           Storyboard.TargetName="position" 
    			                Storyboard.TargetProperty="(UIElement.Opacity)">
    			 <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    		    </DoubleAnimationUsingKeyFrames>
    		    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    			         Duration="00:00:00.0010000" 
    			              Storyboard.TargetName="bufferPosition" 
    			                Storyboard.TargetProperty="(UIElement.Opacity)">
    			 <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    		    </DoubleAnimationUsingKeyFrames>
    		</Storyboard>
    	    </vsm:VisualState>
        <vsm:VisualState x:Name="ShowPositionState"/>
     </vsm:VisualStateGroup>
     <vsm:VisualStateGroup x:Name="ControlStates">
      <vsm:VisualStateGroup.Transitions>
    	<vsm:VisualTransition GeneratedDuration="00:00:02" To="ShowControlPanelState"/>
    	<vsm:VisualTransition From="ShowControlPanelState" GeneratedDuration="00:00:02"/>
      </vsm:VisualStateGroup.Transitions>
      <vsm:VisualState x:Name="ShowControlPanelState">
    	 <Storyboard>
    		<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    		              Storyboard.TargetName="controlBorder" 
    		                   Storyboard.TargetProperty="(UIElement.Opacity)">
    			<SplineDoubleKeyFrame KeyTime="00:00:01" Value="0.8"/>
    		</DoubleAnimationUsingKeyFrames>
    	</Storyboard>
      </vsm:VisualState>
      <vsm:VisualState x:Name="HideControlPanelState"/>
     </vsm:VisualStateGroup>
     </vsm:VisualStateManager.VisualStateGroups>
     <Image x:Name="frameImage" HorizontalAlignment="Center" VerticalAlignment="Center" 
                  Stretch="Uniform" />
     <Grid x:Name="mediaBackground" Background="Black" Visibility="Collapsed">
          <StackPanel MouseLeftButtonUp="mediaPlace_MouseLeftButtonUp" x:Name="mediaPlace" 
                  VerticalAlignment="Center" HorizontalAlignment="Center">
              <MediaElement AutoPlay="False" x:Name="mediaPlayer"/>
          </StackPanel>
     </Grid>
     <Border CornerRadius="30,30,0,30" VerticalAlignment="Bottom" Background="Black" 
                  x:Name="controlBorder" Opacity="0">
         <Grid x:Name="controlGrid" Opacity="0.7" HorizontalAlignment="Stretch" 
                         VerticalAlignment="Bottom" Background="Transparent">
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="Auto"/>
                 <ColumnDefinition Width="*"/>
             </Grid.ColumnDefinitions>
             <cc:PlayPauseButton x:Name="playPauseButton" IsEnabled="False" Width="60" Height="60" 
                         Click="playPauseButton_Click"/>
             <StackPanel Grid.Column="1">
                 <TextBlock x:Name="titleTextBlock" HorizontalAlignment="Center" 
                        VerticalAlignment="Center" 
                        FontSize="16" Foreground="White" Text="Video Tile" TextWrapping="Wrap"/>
                 <mwc:DockPanel LastChildFill="True">
                    <Button Margin="0,0,5,0" mwc:DockPanel.Dock="Left" x:Name="stopButton" 
                            Click="stopButton_Click" Style="{StaticResource StopButtonStyle}"/>
                    <StackPanel Orientation="Horizontal" mwc:DockPanel.Dock="Right">
                       <Slider Width="100" Maximum="1" Value="0.5" LargeChange="0.05" SmallChange="0.01" 
                                     Style="{StaticResource EllipseSliderStyle}" x:Name="volumeSlider" 
                                                    ValueChanged="volumeSlider_ValueChanged"/>
                       <ToggleButton Margin="0,0,5,0" VerticalAlignment="Center" 
                                 Style="{StaticResource muteToggleButtonStyle}" x:Name="muteButton" 
                                         Checked="muteButton_Checked" Unchecked="muteButton_Unchecked"/>
                    </StackPanel>
                    <!--Position TraackBar and Text-->
                    <StackPanel x:Name="positionPanel" MouseEnter="positionPanel_MouseEnter" 
                              MouseLeave="positionPanel_MouseLeave" HorizontalAlignment="Stretch">
                        <Grid>       
                           <Rectangle Fill="#FF7C7A7A" Height="5" VerticalAlignment="Center" 
                        	      x:Name="_base" 
                        	              SizeChanged="_base_SizeChanged" 
                        	                   HorizontalAlignment="Stretch"/>
                           <Rectangle Fill="#FFD7F90E" x:Name="bufferPosition" 
                        	           VerticalAlignment="Center" 
                        	            HorizontalAlignment="Left" Height="5" Width="0"/>
                           <Rectangle Fill="#FFFAFAFB" Height="5" VerticalAlignment="Center" 
                                      HorizontalAlignment="Left" Width="0" x:Name="position"/>
                           <Slider Maximum="1" LargeChange="0.05" SmallChange="0.01" 
                                mwc:DockPanel.Dock="Right" Style="{StaticResource EllipseSliderStyle}" 
                                    IsEnabled="False" x:Name="positionSlider" 
                                          ValueChanged="positionSlider_ValueChanged" 
                                               Opacity="0"/>
                         </Grid>
                         <mwc:DockPanel LastChildFill="False">
                             <TextBlock Foreground="White" mwc:DockPanel.Dock="Right" 
                                     x:Name="mediaDurantionTextBlock" Text="unknown"/>
                             <TextBlock Foreground="White" mwc:DockPanel.Dock="Right" Text="/"/>
                             <TextBlock Foreground="White" mwc:DockPanel.Dock="Right" 
                                        x:Name="mediaPositionTextBlock" Text="00:00:00"/>                                
                         </mwc:DockPanel>
                    </StackPanel>
                  </mwc:DockPanel>
              </StackPanel>
          </Grid>
      </Border>
      <Grid HorizontalAlignment="Center" x:Name="loadingInfo" VerticalAlignment="Center" 
    	              Visibility="Collapsed">
      <-- Omit the loading animation control -->
   </Grid>
</Grid>
    

The main part of the video player is a control panel, which controls the MediaElement to play, pause or stop the media and indicating the position of the media. The visual state controls the appear or disappear of the control panel. There no more interesting thing to say in this XAML file.

But in code, something need to say. The first is how tracking the current position of the media. If you have been study the MediaElement control you may notice there no notify when the playing position changed. So I create a Timer object to track the positon at specified intervals.

Create a globe Timer object.

 /// <summary>
/// A timer object to set the current position
/// </summary>
private Timer setPositionTimer; 

When the media play, start the timer.

 /// <summary>
///  Play the media
/// </summary>
private void PlayMedia()
{
     mediaPlayer.Play();
         
     // omit other code here

     // if can seek, show play position
     if (mediaPlayer.CanSeek)
     {
         if (setPositionTimer == null)
         {
               setPositionTimer = new Timer(this.UpdatePosition, null, 0, 500);
         }
     }
} 

The TimerCallback function called by the Timer object. It's uses a anonymous delegate to update the position of the track bar.

 // Update the play position
private void UpdatePosition(object state)
{
    positionSlider.Dispatcher.BeginInvoke(
          delegate()
          {
               double value = mediaPlayer.Position.TotalSeconds
                             / mediaPlayer.NaturalDuration.TimeSpan.TotalSeconds;
               position.Width = value * _base.ActualWidth;

               mediaPositionTextBlock.Text = mediaPlayer.Position.TotalMinutes.ToString("F2"); ;
          });
}

The second interesting thing is when user move the mouse over the player, the control panel will appear and then disappear if the user hold the mouse still.

When user move the mouse, we use the VisualState make the control panel appear. And we start the downcount to hide the control panel.

// Mouse move in the layout root panel
 private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
 {
      // If mouse move, we show the control panel, then wait a minute 
      // we hide the control panel
      VisualStateManager.GoToState(this, "ShowControlPanelState", true);
      this.Cursor = null;
      HideControlPanel();           
}

The HideControlPanel use a DispatcherTimer object. Here uses DispatcherTimer object because we want direct update the Visual.

/// <summary>
/// A timer when it's occured, the control panel will be hide
/// </summary>
private DispatcherTimer hideControlPanelTimer;

/// <summary>
/// Hide the control panel when a time out
/// </summary>
private void HideControlPanel()
{
      if (hideControlPanelTimer == null)
      {
          hideControlPanelTimer = new DispatcherTimer();
          hideControlPanelTimer.Interval = TimeSpan.FromSeconds(10);
      }
      hideControlPanelTimer.Stop();
      hideControlPanelTimer.Tick += delegate(object s, EventArgs args)
      {
           // when the time out, hide the control panel
           VisualStateManager.GoToState(this, "HideControlPanelState", true);
           this.Cursor = Cursors.None;
           hideControlPanelTimer.Stop();
      };
     hideControlPanelTimer.Start();
}

I say so much about the VideoCarousel control. If you have any problem or advice, please contact me.

History

  • 26rd November, 2008: Initial post
  • 27rd November, 2008: Update source code, fix a bug when the control size changed the player panel can't resize itself, now fix it. And add two event CurrentMediaStateChnaged and SelectedItemChanged.
  • 27rd November, 2008: Update article.
  • 27rd November, 2008: Update source code, fixed a bug when set the AutoTurn to false, the turnning button not appear.
  • License

    This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

    About the Author

    cokkiy


    The God created the world.
    The programer made the world easy.
    I am a programer like c# and c++, so I am writting application in it.
    Creating beautiful application make life easy.
    If you have a project and looking for a man, I'll be say "hi, I am just the man you are looking for."
    Occupation: Chief Technology Officer
    Location: China China

    Article Top
    Sign Up to vote for this article
    You must Sign In to use this message board.
    FAQ FAQ Noise ToleranceSearch Search Messages 
     Layout  Per page   
     Msgs 1 to 11 of 11 (Total in Forum: 11) (Refresh)FirstPrevNext
    GeneralOnline Examplemembercwp429:44 3 Dec '08  
    GeneralRe: Online Examplemembercokkiy19:56 6 Dec '08  
    GeneralRe: Online Examplemembercwp422:53 11 Dec '08  
    GeneralMy vote of 1memberVickyC#21:02 27 Nov '08  
    GeneralRe: My vote of 1membercokkiy3:53 28 Nov '08  
    GeneralInitalization Errormembershermancp17:05 26 Nov '08  
    GeneralRe: Initalization ErrormemberDewey22:15 26 Nov '08  
    AnswerRe: Initalization Errormembercokkiy3:40 27 Nov '08  
    GeneralRe: Initalization Errormembercokkiy3:38 27 Nov '08  
    GeneralRe: Initalization Errormembersegui068:20 6 Dec '08  
    AnswerRe: Initalization Errormembercokkiy19:44 6 Dec '08