MediaElement Sample Code

,

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).

LISTING 7.4. MediaView Class (excerpt)


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).

Image

FIGURE 7.5 Playing a video in the MediaView.

The lower section of the view contains a ScrollViewer, allowing access, for example, to the autoplay CheckBox (see Listing 7.5).

LISTING 7.5. MediaView.xaml ScrollViewer (styling removed)


<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).

LISTING 7.6. MediaView.xaml AppBar


<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).

Image

FIGURE 7.6 Scrolling to the bottom of the view reveals the Balance, Buffering Time, and Auto Play settings.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.12.175