The sample for this section is a media viewer page, which allows you to specify a URL to a media file and view and/or listen to the file. This sample demonstrates the main features of the MediaElement
and gives you a test bed for exploring the MediaElement
’s main properties and methods.
The sample code is located in the MediaView
page and MediaViewModel
class in the downloadable sample code.
The MediaViewModel
class uses four commands to toggle the playback state of the MediaElement
and to mute and unmute audio. When the PlayCommand
is executed, it updates the PlayerState
property, signaling to the view to begin playback. Likewise, the PauseCommand
signals to the view that playback should be paused, as shown in the following excerpt:
public MediaViewModel() : base("Media View")
{
playCommand = new DelegateCommand(
obj =>
{
PlayerState = PlayerState.Playing;
CanPlay = false;
CanPause = true;
});
pauseCommand = new DelegateCommand(
obj =>
{
PlayerState = PlayerState.Paused;
CanPause = false;
CanPlay = true;
});
muteCommand = new DelegateCommand(obj => Muted = true);
unMuteCommand = new DelegateCommand(obj => Muted = false);
}
This example uses the PropertyChanged
event of the viewmodel to signal that the MediaElement
should pause or resume playback.
The MediaViewModel
contains numerous properties that are consumed by the MediaElement
in the view and that for the sake of brevity are not shown.
Much of the code in the view serves to update viewmodel properties when MediaElement
events are raised. For example, when the DownloadProgressChanged
event is raised, the viewmodel’s DownloadProgress
and DownloadProgressOffset
properties are updated (see Listing 7.4).
public partial class MediaView : PhoneApplicationPage
{
public MediaView()
{
InitializeComponent();
MediaViewModel viewModel = new MediaViewModel();
DataContext = viewModel;
viewModel.PropertyChanged += viewModel_PropertyChanged;
}
void viewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "PlayerState")
{
switch (ViewModel.PlayerState)
{
case PlayerState.Stopped:
mediaElement.Stop();
break;
case PlayerState.Playing:
mediaElement.Play();
break;
case PlayerState.Paused:
mediaElement.Pause();
break;
}
}
}
void mediaElement_DownloadProgressChanged(object sender, RoutedEventArgs e)
{
MediaElement element = (MediaElement)sender;
ViewModel.DownloadProgress = element.DownloadProgress;
ViewModel.DownloadProgressOffset = element.DownloadProgressOffset;
}
void mediaElement_BufferingProgressChanged(
object sender, RoutedEventArgs e)
{
MediaElement element = (MediaElement)sender;
ViewModel.BufferingProgress = element.BufferingProgress;
ViewModel.DownloadProgressOffset = element.DownloadProgressOffset;
}
void mediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
MediaElement element = (MediaElement)sender;
ViewModel.PlayLength = element.NaturalDuration.TimeSpan;
}
void mediaElement_CurrentStateChanged(object sender, RoutedEventArgs e)
{
MediaElement element = (MediaElement)sender;
ViewModel.MediaElementState = element.CurrentState;
ViewModel.CanSeek = element.CanSeek;
ViewModel.CanPause = element.CanPause;
}
void mediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
ViewModel.HandleMediaFailed(e.ErrorException);
}
}
When a command, such as the PlayCommand
, is executed via a button in the view, the viewmodel causes the MediaElement
to play by updating its PlayerState
property, which then raises the PropertyChanged
event, handled in the view.
Various MediaElement
properties are bound to the viewmodel, as shown:
<MediaElement x:Name="mediaElement" Grid.Row="1"
DownloadProgressChanged="mediaElement_DownloadProgressChanged"
BufferingProgressChanged="mediaElement_BufferingProgressChanged"
Source="{Binding MediaUri, Mode=TwoWay}"
Position="{Binding Position, Mode=TwoWay}"
MediaOpened="mediaElement_MediaOpened"
CurrentStateChanged="mediaElement_CurrentStateChanged"
AutoPlay="{Binding AutoPlay}"
BufferingTime="{Binding BufferingTime, Mode=TwoWay}"
IsMuted="{Binding Muted}"
Volume="{Binding Volume}"
Balance="{Binding Balance}"
MediaFailed="mediaElement_MediaFailed" />
Two viewmodel properties are employed to track and control the position of the current media file: Position
and SliderPosition
.
Note
Avoid placing a two-way data binding on the MediaElement.Position
property to a source object that raises a PropertyChanged
event. Doing so causes the MediaElement
to stutter as it continually tries to return to the Position
at the time when event was raised.
The view contains two sections. The upper section holds the MediaElement
, and the lower holds various controls for modifying the MediaElement
properties, for monitoring download progress, and so forth. There is a position Slider
that tracks the position of the media and allows the user to seek to a different position. Moving the position Slider
causes the download and buffer-related progress bars to provide feedback to the user (see Figure 7.5).
The lower section of the view contains a ScrollViewer
, allowing access, for example, to the autoplay CheckBox
(see Listing 7.5).
<ScrollViewer Height="400" Grid.Row="1"
VerticalScrollBarVisibility="Visible">
<StackPanel Margin="12,0,12,0">
<TextBlock Text="Position" />
<TextBlock Text="{Binding SliderPosition}" />
<Slider Value="{Binding SliderPosition, Mode=TwoWay,
Converter={StaticResource TimespanToDoubleConverter}}"
Maximum="{Binding PlayLength,
Converter={StaticResource TimespanToDoubleConverter}}"
IsEnabled="{Binding CanSeek}" />
<TextBlock Text="{Binding MediaElementState}" />
<TextBlock Text="{Binding Message}" />
<TextBlock Text="Download Progress" />
<ProgressBar Value="{Binding DownloadProgress}"
Minimum="0" Maximum="1" />
<TextBlock Text="Download Progress Offset" />
<ProgressBar Value="{Binding DownloadProgressOffset}"
Minimum="0" Maximum="1" />
<TextBlock Text="Buffer Progress" />
<ProgressBar Value="{Binding BufferingProgress}"
Minimum="0" Maximum="1" />
<TextBlock Text="Volume" />
<Slider Value="{Binding Volume, Mode=TwoWay}"
Maximum="1" LargeChange=".1" />
<TextBlock Text="Balance" />
<Slider Value="{Binding Balance, Mode=TwoWay}"
Minimum="-1" Maximum="1" LargeChange=".1" />
<TextBlock Text="Buffering Time" />
<TextBlock Text="{Binding BufferingTime}" />
<Slider Value="{Binding BufferingTime, Mode=TwoWay,
Converter={StaticResource TimespanToDoubleConverter}}"
Maximum="60000" LargeChange="10000" />
<CheckBox IsChecked="{Binding AutoPlay, Mode=TwoWay}"
Content="Auto Play" />
</StackPanel>
</ScrollViewer>
An AppBar
control is used in the sample page, which provides data binding and commanding support. A custom AppBarToggleButton
allows the use of two commands in conjunction with a Toggled
property, which allows one of the commands to be enabled depending on the value of the property. If the Toggled
property is false
, Command1
, Text1
, and Icon1Uri
are used; if set to true
, the second set is used. For more information regarding the ApplicationBar
, and the custom AppBar
control used here, see Chapter 8.
PlayCommand
becomes active if the CanPlay
property of the viewmodel is true
; when the CanPlay
property evaluates to false, the button text is replaced along with its icon, and the PauseCommand
becomes active (see Listing 7.6).
<u:AppBar IsEnabled="True"
IsVisible="True"
IsMenuEnabled="True">
<u:AppBarToggleButton
Command1="{Binding PauseCommand}"
Text1="Pause"
Icon1Uri="/ControlExamples/MediaView/Images/Pause.png"
Command2="{Binding PlayCommand}"
Text2="Play"
Icon2Uri="/ControlExamples/MediaView/Images/Play.png"
Toggled="{Binding CanPlay}" />
<u:AppBarToggleButton
x:Name="button_Mute"
Command1="{Binding MuteCommand}"
Text1="Mute"
Icon1Uri="/ControlExamples/MediaView/Images/Speaker.png"
Command2="{Binding UnMuteCommand}"
Text2="Un-Mute"
Icon2Uri="/ControlExamples/MediaView/Images/Mute.png"
Toggled="{Binding Muted}" />
</u:AppBar>
Tapping the mute button executes the MuteCommand
, which updates the Muted
property in the viewmodel, updating the MediaElement
control via a data binding. When muted, the property changed event for the Muted
property indicates to the AppBarToggleButton
that Command2
, Text2
, and Icon2Uri
should be used (see Figure 7.6).
18.217.12.175