创建自定义传输控件
MediaPlayerElement 具有可自定义的 XAML 传输控件,用于管理 Windows 应用中的音频和视频内容控件。 在这里,我们演示如何自定义 MediaTransportControls 模板。 我们将向你演示如何使用溢出菜单、添加自定义按钮和修改滑块。
重要 API: MediaPlayerElement、 MediaPlayerElement.AreTransportControlsEnabled、 MediaTransportControls
在开始之前,应熟悉 MediaPlayerElement 和 MediaTransportControls 类。 有关详细信息,请参阅 MediaPlayerElement 控件指南。
提示
本主题中的示例基于 媒体传输控件示例。 可以下载示例以查看并运行已完成的代码。
注意
MediaPlayerElement 仅在 Windows 10 版本 1607 及更高版本中可用。 如果要为早期版本的 Windows 10 开发应用,则需要改用 MediaElement。 此页上 的所有示例也适用于 MediaElement 。
何时应自定义模板?
MediaPlayerElement 具有内置的传输控件,这些控件设计为在大多数视频和音频播放应用中都正常运行。 它们由 MediaTransportControls 类提供,其中包括用于播放、停止和导航媒体、调整音量、切换全屏、强制转换到第二台设备、启用字幕、切换音频轨以及调整播放速率的按钮。 MediaTransportControls 具有属性,可用于控制是否显示和启用每个按钮。 还可以设置 IsCompact 属性以指定控件是显示在一行还是两行中。
但是,在某些情况下,可能需要进一步自定义控件的外观或更改其行为。 以下是一些示例:
- 更改图标、滑块行为和颜色。
- 将不太常用的命令按钮移动到溢出菜单中。
- 更改命令在调整控件大小时退出的顺序。
- 提供不在默认集中的命令按钮。
注意
如果屏幕上没有足够的空间,屏幕上可见的按钮将以预定义的顺序退出内置传输控件。 若要更改此排序或放置不适合溢出菜单的命令,需要自定义控件。
可以通过修改默认模板来自定义控件的外观。 若要修改控件的行为或添加新命令,可以创建自定义控件,该控件派生自 MediaTransportControls。
提示
可自定义控件模板是 XAML 平台的一项强大功能,但也需要考虑后果。 自定义模板时,它将成为应用的静态部分,因此不会收到通过Microsoft对模板进行的任何平台更新。 如果模板更新由Microsoft进行,则应获取新模板并重新修改它,以获取更新后的模板的好处。
模板结构
ControlTemplate 是默认样式的一部分。 可以将此默认样式复制到项目中以对其进行修改。 ControlTemplate 分为类似于其他 XAML 控件模板的部分。
- 模板的第一部分包含 MediaTransportControls 各个组件的 Style 定义。
- 第二部分定义 MediaTransportControls 使用的各种视觉状态。
- 第三部分包含 包含各种 MediaTransportControls 元素并定义组件布局方式的 Grid 。
注意
有关修改模板的详细信息,请参阅 控件模板。 可以在 IDE 中使用文本编辑器或类似编辑器打开 (Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\(SDK version)\Generic 中的 XAML 文件。 每个控件的默认样式和模板在 generic.xaml 文件中定义。 可以通过搜索“MediaTransportControls”在 generic.xaml 中找到 MediaTransportControls 模板。
以下部分介绍如何自定义传输控件的多个主要元素:
- Slider:允许用户在其媒体上进行推移,同时显示相关进度
- CommandBar:包含所有按钮。 有关详细信息,请参阅 MediaTransportControls 参考主题的“剖析”部分。
自定义传输控件
如果只想修改 MediaTransportControls 的外观,可以创建默认控件样式和模板的副本,然后对其进行修改。 但是,如果还需要添加或修改控件的功能,则需要创建派生自 MediaTransportControls 的新类。
重新模板化控件
自定义 MediaTransportControls 默认样式和模板
- 将 MediaTransportControls 样式和模板中的默认样式复制到项目中的 ResourceDictionary。
- 为样式提供一个 x:Key 值来标识它,如下所示。
<Style TargetType="MediaTransportControls" x:Key="myTransportControlsStyle">
<!-- Style content ... -->
</Style>
- 使用 MediaTransportControls 将 MediaPlayerElement 添加到 UI。
- 将 MediaTransportControls 元素的 Style 属性设置为自定义样式资源,如下所示。
<MediaPlayerElement AreTransportControlsEnabled="True">
<MediaPlayerElement.TransportControls>
<MediaTransportControls Style="{StaticResource myTransportControlsStyle}"/>
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
有关修改样式和模板的详细信息,请参阅设置控件和控件模板的样式。
创建派生控件
若要添加或修改传输控件的功能,必须创建派生自 MediaTransportControls 的新类。 调用 CustomMediaTransportControls
的派生类显示在 媒体传输控件示例 和此页面的其余示例中。
创建一个派生自 MediaTransportControls 的新类
- 向你的项目中添加一个新类文件。
- 在 Visual Studio 中,选择“项目”>“添加类”。 “添加新项” 对话框随即打开。
- 在“添加新项”对话框中,输入类文件的名称,然后单击“添加”。 (在媒体传输控件示例中,类命名为
CustomMediaTransportControls
.)
- 修改类代码以派生自 MediaTransportControls 类。
public sealed class CustomMediaTransportControls : MediaTransportControls
{
}
- 将 MediaTransportControls 的默认样式复制到项目中的 ResourceDictionary 中。 这是你修改的样式和模板。 (在媒体传输控件示例中,将创建一个名为“主题”的新文件夹,并将名为 generic.xaml 的 ResourceDictionary 文件添加到其中。
- 将 样式的 TargetType 更改为新的自定义控件类型。 (在示例中,TargetType 更改为
local:CustomMediaTransportControls
.)
xmlns:local="using:CustomMediaTransportControls">
...
<Style TargetType="local:CustomMediaTransportControls">
- 设置自定义类的 DefaultStyleKey。 这会告知自定义类将 Style 与 TargetType 配合使用
local:CustomMediaTransportControls
。
public sealed class CustomMediaTransportControls : MediaTransportControls
{
public CustomMediaTransportControls()
{
this.DefaultStyleKey = typeof(CustomMediaTransportControls);
}
}
- 将 MediaPlayerElement 添加到 XAML 标记,并向其添加自定义传输控件。 需要注意的一点是,用于隐藏、显示、禁用和启用默认按钮的 API 仍使用自定义模板。
<MediaPlayerElement Name="MediaPlayerElement1" AreTransportControlsEnabled="True" Source="video.mp4">
<MediaPlayerElement.TransportControls>
<local:CustomMediaTransportControls x:Name="customMTC"
IsFastForwardButtonVisible="True"
IsFastForwardEnabled="True"
IsFastRewindButtonVisible="True"
IsFastRewindEnabled="True"
IsPlaybackRateButtonVisible="True"
IsPlaybackRateEnabled="True"
IsCompact="False">
</local:CustomMediaTransportControls>
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
现在可以修改控件样式和模板来更新自定义控件的外观,以及用于更新其行为的控件代码。
使用溢出菜单
可以将 MediaTransportControls 命令按钮移动到溢出菜单中,以便隐藏不太常用的命令,直到用户需要它们。
在 MediaTransportControls 模板中,命令按钮包含在 CommandBar 元素中。 命令栏具有主要命令和辅助命令的概念。 主要命令是默认情况下显示在控件中的按钮,并且始终可见(除非禁用该按钮、隐藏按钮或没有足够的空间)。 辅助命令显示在用户单击省略号 (...) 按钮时显示的溢出菜单中。 有关详细信息,请参阅 应用栏和命令栏 文章。
若要将元素从命令栏主命令移动到溢出菜单,需要编辑 XAML 控件模板。
将命令移动到“溢出”菜单:
- 在控件模板中,找到名为
MediaControlsCommandBar
的 CommandBar 元素。 - 将 SecondaryCommands 节添加到 CommandBar 的 XAML。 将其置于 PrimaryCommands 的结束标记之后。
<CommandBar x:Name="MediaControlsCommandBar" ... >
<CommandBar.PrimaryCommands>
...
<AppBarButton x:Name='PlaybackRateButton'
Style='{StaticResource AppBarButtonStyle}'
MediaTransportControlsHelper.DropoutOrder='4'
Visibility='Collapsed'>
<AppBarButton.Icon>
<FontIcon Glyph=""/>
</AppBarButton.Icon>
</AppBarButton>
...
</CommandBar.PrimaryCommands>
<!-- Add secondary commands (overflow menu) here -->
<CommandBar.SecondaryCommands>
...
</CommandBar.SecondaryCommands>
</CommandBar>
若要使用命令填充菜单,请将所需 AppBarButton 对象的 XAML 从 PrimaryCommand 剪切并粘贴到 SecondaryCommands。 在此示例中,我们将转到
PlaybackRateButton
溢出菜单。将标签添加到按钮并删除样式信息,如下所示。 由于溢出菜单由文本按钮组成,因此必须将文本标签添加到按钮,并删除设置按钮高度和宽度的样式。 否则,它不会在溢出菜单中正确显示。
<CommandBar.SecondaryCommands>
<AppBarButton x:Name='PlaybackRateButton'
Label='Playback Rate'>
</AppBarButton>
</CommandBar.SecondaryCommands>
重要
你仍必须使按钮可见并启用它,才能在溢出菜单中使用它。 在此示例中,除非 IsPlaybackRateButtonVisible 属性为 true,否则 PlaybackRateButton 元素在溢出菜单中不可见。 除非 IsPlaybackRateEnabled 属性为 true,否则不会启用它。 设置这些属性显示在上一部分。
添加自定义按钮
你可能想要自定义 MediaTransportControls 的一个原因是向控件添加自定义命令。 无论是将其添加为主命令还是辅助命令,创建命令按钮和修改其行为的过程都是相同的。 在 媒体传输控件示例中,将“分级”按钮添加到主要命令。
添加自定义命令按钮
- 创建 AppBarButton 对象并将其添加到控件模板中的 CommandBar。
<AppBarButton x:Name="LikeButton"
Icon="Like"
Style="{StaticResource AppBarButtonStyle}"
MediaTransportControlsHelper.DropoutOrder="3"
VerticalAlignment="Center" />
必须在合适的位置将它添加到 CommandBar。 (有关详细信息,请参阅“使用溢出菜单”部分。它在 UI 中的位置取决于按钮在标记中的位置。 例如,如果希望该按钮在主要命令中显示为最后一个元素,请将其添加到主要命令列表的最末尾。
还可以自定义按钮的图标。 有关详细信息,请查看 AppBarButton 参考。
- 在 OnApplyTemplate 重写中,从模板获取按钮并为其 Click 事件注册处理程序。 此代码位于类中
CustomMediaTransportControls
。
public sealed class CustomMediaTransportControls : MediaTransportControls
{
// ...
protected override void OnApplyTemplate()
{
// Find the custom button and create an event handler for its Click event.
var likeButton = GetTemplateChild("LikeButton") as Button;
likeButton.Click += LikeButton_Click;
base.OnApplyTemplate();
}
//...
}
- 将代码添加到 Click 事件处理程序,以执行单击按钮时发生的操作。 下面是该类的完整代码。
public sealed class CustomMediaTransportControls : MediaTransportControls
{
public event EventHandler< EventArgs> Liked;
public CustomMediaTransportControls()
{
this.DefaultStyleKey = typeof(CustomMediaTransportControls);
}
protected override void OnApplyTemplate()
{
// Find the custom button and create an event handler for its Click event.
var likeButton = GetTemplateChild("LikeButton") as Button;
likeButton.Click += LikeButton_Click;
base.OnApplyTemplate();
}
private void LikeButton_Click(object sender, RoutedEventArgs e)
{
// Raise an event on the custom control when 'like' is clicked.
var handler = Liked;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
修改滑块
MediaTransportControls 的“seek”控件由 Slider 元素提供。 自定义它的一种方法是更改搜寻行为的粒度。
默认查找滑块分为 100 个部分,因此搜寻行为仅限于该多个部分。 可以通过从 MediaPlayerElement.MediaPlayer 上的 MediaOpened 事件处理程序中的 XAML 可视化树获取滑块来更改查找滑块的粒度。 此示例演示如何使用 VisualTreeHelper 获取对滑块的引用,如果媒体超过 120 分钟,则将滑块的默认步骤频率从 1% 更改为 0.1% (1000 步骤)。 MediaPlayerElement 命名 MediaPlayerElement1
。
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MediaPlayerElement1.MediaPlayer.MediaOpened += MediaPlayerElement_MediaPlayer_MediaOpened;
base.OnNavigatedTo(e);
}
private void MediaPlayerElement_MediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
FrameworkElement transportControlsTemplateRoot = (FrameworkElement)VisualTreeHelper.GetChild(MediaPlayerElement1.TransportControls, 0);
Slider sliderControl = (Slider)transportControlsTemplateRoot.FindName("ProgressSlider");
if (sliderControl != null && MediaPlayerElement1.NaturalDuration.TimeSpan.TotalMinutes > 120)
{
// Default is 1%. Change to 0.1% for more granular seeking.
sliderControl.StepFrequency = 0.1;
}
}