3. Coding the Application
In Solution Explorer, open MainPage.xaml.cs and replace the code you find there with the following C# code blocks that will implement the media player's functions.
3.1. Specifying the Namespaces
Begin by listing the namespaces the application will use. Notice the inclusion of Microsoft.Phone.Tasks that will allow us to launch Windows Phone's default media player. As for the MediaElement, it is declared in the XAML page, which you will simply reference here by the control's name.
using System;
using System.Windows;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Tasks;
namespace MediaPlayerDemo
{
public partial class MainPage : PhoneApplicationPage
3.2. Initializing Variables
The variable _updatingMediaTimeline is an extremely important variable that stops the infinite loop in this demo. By setting _updatingMediaTimeline to true while the media timeline (Slider control) is being updated during the CompositionTarget.Rendering
event, the media's backward and forward event will wait to be processed
until the timeline update is completed. Another way to look at this
complexity is to see the purpose of the Slider control that is responsible for displaying the timeline of the media being played. But the Slider
control is also responsible for allowing the user to interact to drag
the slider forward or backward in order to move the media position. _updatingMediaTimeline will allow only one specific behavior to happen in the Slider control, thereby avoiding unwanted application behavior.
private bool _updatingMediaTimeline;
public MainPage()
{
InitializeComponent();
_updatingMediaTimeline = false;
// rewinds the media player to the beginning
mediaPlayer.Position = System.TimeSpan.FromSeconds(0);
3.3. Handling Video Download Progress
As the video file
download progresses, you will be receiving the percentage of the file
got downloaded and you will be displaying the progress updates back to
the user by updating the lblDownload.
// Download indicator
mediaPlayer.DownloadProgressChanged += (s, e) =>
{
lblDownload.Text = string.Format("Downloading {0:0.0%}",
mediaPlayer.DownloadProgress);
};
3.4. Handling Video Buffering
You will be setting video
BufferingTime property and as the video buffering time progresses you
will receive a callback where you will update lblBuffering.
// Handle media buffering
mediaPlayer.BufferingTime =
TimeSpan.FromSeconds(Convert.ToDouble(txtBufferingTime.Text));
mediaPlayer.BufferingProgressChanged += (s, e) =>
{
lblBuffering.Text = string.Format("Buffering {0:0.0%}",
mediaPlayer.BufferingProgress);
};
3.5. Showing Time Elapsed in the Media Player
CompositionTarget.Rendering is a frame-based event that will fire once per frame, allowing you to update the media timeline (Slider
control) that reflects how much of the media is played. By default the
event will fire 60 times in one second. You can check this by checking
the value of Application.Current.Host.Settings.MaxFrameRate. By using the CompositionTarget.Rendering event, you will be able to see the smooth media player timeline filling up as the media plays.
// Updates the media time line (slider control) with total time played
// and updates the status with the time played
CompositionTarget.Rendering += (s, e) =>
{
_updatingMediaTimeline = true;
TimeSpan duration = mediaPlayer.NaturalDuration.TimeSpan;
if (duration.TotalSeconds != 0)
{
double percentComplete =
mediaPlayer.Position.TotalSeconds / duration.TotalSeconds;
mediaTimeline.Value = percentComplete;
TimeSpan mediaTime = mediaPlayer.Position;
string text = string.Format("{0:00}:{1:00}",
(mediaTime.Hours * 60) + mediaTime.Minutes, mediaTime.Seconds);
if (lblStatus.Text != text)
lblStatus.Text = text;
_updatingMediaTimeline = false;
}
};
}
When defining the event handler of CompositionTarget.Rendering, you can use the lambda expression to create a delegate that contains the programming logic. For example, you can rewrite CompositionTarget.Rendering += (s, e) => { ... } by first declaring the event handler CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering) and then creating a method void CompositionTarget_Rendering(object sender, EventArgs e) { ... }.
Using the lambda expression technique makes the code much more readable
and in this demo project gives you the ability to group the relevant
code together. For more information on the lambda expression, please
refer to http://msdn.microsoft.com/en-us/library/bb397687.aspx.
|
|
3.6. Implementing the Pause Button
When the Pause button is clicked, invoke MediaElement.Pause
to pause the media player. Notice also here that you are updating the
Status label, communicating to the user the media is in pause mode. Also
notice that for unknown reasons, the media player might not be able to
pause. You can use mediaPlayer.CanPause to make sure you can pause and otherwise set the Status label to warn the user it could not pause.
private void btnPause_Click(object sender, RoutedEventArgs e)
{
if (mediaPlayer.CanPause)
{
mediaPlayer.Pause();
lblStatus.Text = "Paused";
}
else
{
lblStatus.Text = "Can not be Paused. Please try again!";
}
}
3.7. Implementing the Stop Button
When the stop button is clicked, invoke MediaElement.Stop to stop the media player and then rewind the media player back to the beginning and update the Status label as "Stopped."
private void btnStop_Click(object sender, RoutedEventArgs e)
{
mediaPlayer.Stop();
mediaPlayer.Position = System.TimeSpan.FromSeconds(0);
lblStatus.Text = "Stopped";
}
3.8. Implementing the Play Button
When the play button is clicked, invoke MediaElement.Play to play the media player.
private void btnPlay_Click(object sender, RoutedEventArgs e)
{
mediaPlayer.Play();
}
3.9. Implementing the Mute Button
When the Mute button is clicked, set MediaElement.IsMuted to true in order to mute the sound or set it to false to turn on the sound.
private void btnMute_Click(object sender, RoutedEventArgs e)
{
if (lblSoundStatus.Text.Equals("Sound On", StringComparison.CurrentCultureIgnoreCase))
{
lblSoundStatus.Text = "Sound Off";
mediaPlayer.IsMuted = true;
}
else
{
lblSoundStatus.Text = "Sound On";
mediaPlayer.IsMuted = false;
}
}
NOTE
To mute the player, you could have set MediaElement.Volume to zero instead of setting the IsMuted property to true, as we did in our example.
3.10. Implementing Seek
When the Slider control that displays the timeline of the media is clicked or dragged, MediaElement.Position moves either forward or backward, depending on the user's input on the Slider control. See Figure 15-3 for dragging the slider to the right in order to move forward in the video timeline.
private void mediaTimeline_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
if (!_updatingMediaTimeline && mediaPlayer.CanSeek)
{
TimeSpan duration = mediaPlayer.NaturalDuration.TimeSpan;
int newPosition = (int)(duration.TotalSeconds * mediaTimeline.Value);
mediaPlayer.Position = new TimeSpan(0, 0, newPosition);
}
}