Skip to main content
Email Password   helpLost your password?

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

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.
  • You must Sign In to use this message board.
     
     
    Per page   
     FirstPrevNext
    QuestionPlease i really need help? Pin
    adavecohen
    18:20 9 Nov '09  
    GeneralInitialize error on silverlight 3.0 [modified] Pin
    dingdong1
    11:36 21 Oct '09  
    GeneralRe: Initialize error on silverlight 3.0 Pin
    cokkiy
    3:01 22 Oct '09  
    GeneralMy vote of 1 Pin
    Shakeel Hussain
    5:38 29 Jul '09  
    QuestionMedia Failed Pin
    mcirullo1
    11:04 7 Jun '09  
    AnswerRe: Media Failed Pin
    cokkiy
    3:33 8 Jun '09  
    GeneralRe: Media Failed Pin
    elvis_pan
    20:00 14 Jun '09  
    GeneralWPF Carousel Pin
    Ernesto Herrera
    6:22 4 Mar '09  
    GeneralOnline Example Pin
    cwp42
    9:44 3 Dec '08  
    GeneralRe: Online Example Pin
    cokkiy
    19:56 6 Dec '08  
    GeneralRe: Online Example Pin
    cwp42
    2:53 11 Dec '08  
    GeneralMy vote of 1 Pin
    VickyC#
    21:02 27 Nov '08  
    GeneralRe: My vote of 1 Pin
    cokkiy
    3:53 28 Nov '08  
    GeneralInitalization Error Pin
    shermancp
    17:05 26 Nov '08  
    GeneralRe: Initalization Error Pin
    Dewey
    22:15 26 Nov '08  
    AnswerRe: Initalization Error Pin
    cokkiy
    3:40 27 Nov '08  
    GeneralRe: Initalization Error Pin
    cokkiy
    3:38 27 Nov '08  
    GeneralRe: Initalization Error Pin
    segui06
    8:20 6 Dec '08  
    AnswerRe: Initalization Error Pin
    cokkiy
    19:44 6 Dec '08  
    GeneralRe: Initalization Error Pin
    MyDrocks
    16:02 9 Jan '09  


    Last Updated 22 Oct 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2009