The media player launcher is used to launch the built-in Media Player app to play a specified media file (see Figure 14.12).
Media files can be stored either locally on the device or externally using an absolute Uri
. If stored locally, the MediaPlayerLauncher.Media
property must be assigned a relative Uri
to the file location. Relative Uri
s are used for files located in either isolated storage or in the app’s XAP file.
Files downloaded from the Internet are placed in isolated storage, whereas files accompanying the app are placed into the app’s XAP file during the build process.
Tip
To include a media file in your XAP file be sure to set its Build Action to Content.
The MediaPlayerLauncher.Location
property allows you to specify where the content is located, either in the XAP, isolated storage, or on a remote server.
The MediaPlayerLauncher.Location
property must be set to MediaLocationType.Install
for media files located within the app’s XAP file. For content located in isolated storage, MediaLocationType.Data
should be used. If not specified, MediaPlayerLauncher.Location
defaults to MediaLocationType.Data
. For content located on a remote server, MediaLocationType.None
is used along with an absolute Uri
. If MediaLocationType.None
is used in conjunction with a relative Uri
, a FileNotFoundException
is raised when the MediaPlayerLauncher.Show
method is called.
You can optionally specify that one or more playback controls should be shown by the Media Player, by setting the MediaPlayerLauncher.Controls
property using bitwise OR combinations of the MediaPlaybackControls
enum values.
The following is the list of possible MediaPlaybackControls
enum values:
All—All controls. The equivalent of using OR to combine all the other members of the enumeration.
FastForward—The fast-forward control.
None—No controls are shown.
Pause—The pause control.
Rewind—The rewind control.
Skip—The skip control.
Stop—The stop control.
If not specified, the MediaPlayerLauncher.Controls
property defaults to MediaPlaybackControls.All
, and the rewind, pause, and fast-forward buttons are displayed by the Media Player app.
Note
Although it is possible to specify the Skip and Stop controls, the controls are not displayed, and it does not affect the Media Player app.
The following example shows how to use the MediaPlayerLauncher
to play a local media file in the Media Player app, displaying a Pause and a Stop button:
MediaPlayerLauncher mediaPlayerLauncher
= new MediaPlayerLauncher
{
Media = new Uri("LaunchersAndChoosers/Video.wmv", UriKind.Relative),
Location = MediaLocationType.Install,
Controls = MediaPlaybackControls.Pause | MediaPlaybackControls.Stop
};
mediaPlayerLauncher.Show();
To specify a nonlocal media file, use an absolute Uri
, as demonstrated in the following example:
MediaPlayerLauncher mediaPlayerLauncher
= new MediaPlayerLauncher
{
Media = new Uri("http://www.example.com/Video.wmv",
UriKind.Absolute),
Controls = MediaPlaybackControls.All
};
mediaPlayerLauncher.Show();
Example code for the MediaPlayerLauncher
can be found in the MediaPlayerLauncherViewModel
, in the downloadable sample code.
The MediaPlayerLauncherView
page has a button that executes an ICommand
named SearchCommand
in the viewmodel.
When executed, the command instantiates a MediaPlayerLauncher
and populates its Controls
property with the playbackControls
field, using a lambda expression (see Listing 14.2).
The lambda Aggregate
extension method combines the values in the IEnumerable
collection of MediaPlaybackControls
enum flags by OR’ing each one with the previous result.
public class MediaPlayerLauncherViewModel : ViewModelBase
{
public MediaPlayerLauncherViewModel()
: base("Media Player Launcher")
{
launchCommand = new DelegateCommand(
delegate
{
MediaPlayerLauncher mediaPlayerLauncher
= new MediaPlayerLauncher
{
//Media = new Uri("http://example.com/Video.wmv",
// UriKind.Absolute),
Media = new Uri("LaunchersAndChoosers/Video.wmv",
UriKind.Relative),
Location = MediaLocationType.Install,
};
if (playbackControls.Count > 0)
{
mediaPlayerLauncher.Controls
= playbackControls.Aggregate((a, b) => a | b);
}
mediaPlayerLauncher.Show();
});
}
readonly List<MediaPlaybackControls> mediaPlaybackControls
= new List<MediaPlaybackControls>
{
MediaPlaybackControls.FastForward,
MediaPlaybackControls.Pause,
MediaPlaybackControls.Rewind,
/* Not used by Media Player. */
//MediaPlaybackControls.Skip,
//MediaPlaybackControls.Stop
};
public IEnumerable<MediaPlaybackControls> AvailablePlaybackControls
{
get
{
return mediaPlaybackControls;
}
}
readonly ObservableCollection<MediaPlaybackControls> playbackControls
= new ObservableCollection<MediaPlaybackControls>();
public ObservableCollection<MediaPlaybackControls> PlaybackControls
{
get
{
return playbackControls;
}
}
...
}
The view presents the list of available playback controls in a ListBox
. A custom attached property is used to provide quasi binding support for the SelectedItems
property of the ListBox
. This attached property is discussed further in the next section. See the following excerpt:
<StackPanel x:Name="ContentPanel" Grid.Row="1">
<TextBlock Text="Media Player Controls:"
Style="{StaticResource PhoneTextTitle2Style}" />
<ListBox ItemsSource="{Binding AvailablePlaybackControls}"
SelectionMode="Multiple"
unleashed:SelectedItems.Items="{Binding PlaybackControls}"
Margin="15">
</ListBox>
<Button Command="{Binding LaunchCommand}"
Content="Launch Media Player" />
<TextBlock Text="{Binding Message}"
Style="{StaticResource PhoneTextMessageStyle}" />
</StackPanel>
Multiple items in the ListBox
can be selected, and the Launch Media Player button initiates the LaunchCommand
in the viewmodel (see Figure 14.13).
Unfortunately, the ListBox.SelectedItems
property is not a DependencyProperty
, which means it cannot be the target of a databinding. A custom attached property is included in the downloadable sample code that allows you to bind the SelectedItems
property to a collection (see Listing 14.3).
The SelectedItems
class contains two DependencyProperty
s: an ItemsProperty
and a SelectedItemsBehaviorProperty
. ItemsProperty
specifies the source property of the DataContext
and is used to assign the selected items to the ListBox
’s DataContext
. When the SelectionChanged
event of the ListBox
is raised, the DataContext
’s property is updated.
The SelectedItemsBehavior
class contains the logic for updating the list of selected items, which also relies on the DataContextChangedListener
class, which raises an event when the DataContext
of the ListBox
changes. For more information on the DataContextChangedListener
, see Chapter 26, “Validating User Input.”
An instance of the SelectedItemsBehavior
is associated with the ListBox
using the SelectedItemsBehaviorProperty
.
public static class SelectedItems
{
public static readonly DependencyProperty ItemsProperty
= DependencyProperty.RegisterAttached(
"Items",
typeof(IList),
typeof(SelectedItems),
new PropertyMetadata(null, ItemsPropertyChanged));
public static void SetItems(ListBox listBox, IList list)
{
listBox.SetValue(ItemsProperty, list);
}
public static IList GetItems(ListBox listBox)
{
return (IList)listBox.GetValue(ItemsProperty);
}
static readonly DependencyProperty SelectedItemsBehaviorProperty
= DependencyProperty.RegisterAttached(
"SelectedItemsBehavior",
typeof(SelectedItemsBehavior),
typeof(ListBox), null);
static void ItemsPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as ListBox;
if (target != null)
{
GetOrCreateBehavior(target, (IList)e.NewValue);
}
}
static SelectedItemsBehavior GetOrCreateBehavior(
ListBox listBox, IList list)
{
var behavior = (SelectedItemsBehavior)listBox.GetValue(
SelectedItemsBehaviorProperty);
if (behavior == null)
{
behavior = new SelectedItemsBehavior(listBox, list);
listBox.SetValue(SelectedItemsBehaviorProperty, behavior);
}
return behavior;
}
class SelectedItemsBehavior
{
readonly ListBox listBox;
readonly IList sourceList;
public SelectedItemsBehavior(ListBox listBox, IList sourceList)
{
this.listBox = ArgumentValidator.AssertNotNull(listBox, "listBox");
this.sourceList = ArgumentValidator.AssertNotNull(
sourceList, "sourceList");
this.listBox.SelectionChanged += OnSelectionChanged;
DataContextChangedListener.Subscribe(listBox, OnDataContextChanged);
}
void OnDataContextChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateList();
}
void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
UpdateList();
}
void UpdateList()
{
sourceList.Clear();
foreach (object item in listBox.SelectedItems)
{
sourceList.Add(item);
}
}
}
}
3.145.169.109