创建自定义传输控件

MediaPlayerElement 具有可自定义的 XAML 传输控制,可用于管理 Windows 应用中的音频和视频内容。 在这里,我们演示如何自定义 MediaTransportControls 模板。 我们将介绍如何使用溢出菜单,添加自定义按钮并修改滑块。

重要 APIMediaPlayerElementMediaPlayerElement.AreTransportControlsEnabledMediaTransportControls

在开始之前,应熟悉 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 模板。

以下部分介绍如何自定义传输控件的多个主要元素:

  • 滑块:允许用户清理其媒体并显示进度
  • CommandBar:包含所有按钮。 有关详细信息,请参阅 MediaTransportControls 参考主题的“结构”部分。

自定义传输控件

如果只想修改 MediaTransportControls 的外观,可以创建默认控件样式和模板的副本,然后对其进行修改。 但是,如果还需要添加或修改控件的功能,则需要创建派生自 MediaTransportControls 的新类。

重新模板化控件

自定义 MediaTransportControls 默认样式和模板

  1. 将 MediaTransportControls 样式和模板中的默认样式复制到项目中的 ResourceDictionary。
  2. 为样式提供一个 x:Key 值来标识它,如下所示。
<Style TargetType="MediaTransportControls" x:Key="myTransportControlsStyle">
    <!-- Style content ... -->
</Style>
  1. 使用 MediaTransportControls 将 MediaPlayerElement 添加到 UI。
  2. 将 MediaTransportControls 元素的 Style 属性设置为自定义样式资源,如下所示。
<MediaPlayerElement AreTransportControlsEnabled="True">
    <MediaPlayerElement.TransportControls>
        <MediaTransportControls Style="{StaticResource myTransportControlsStyle}"/>
    </MediaPlayerElement.TransportControls>
</MediaPlayerElement>

有关修改样式和模板的更多信息,请查看 样式控件控件模板

创建派生控件

若要添加或修改传输控件的功能,必须创建派生自 MediaTransportControls 的新类。 CustomMediaTransportControls 的派生类显示在 媒体传输控件示例 和页面上的其他示例中。

创建派生自 MediaTransportControls 的新类

  1. 向项目添加新的类文件。
    • 在 Visual Studio 中,选择“项目 > 添加类”。 此时会打开“添加新项”对话框。
    • 在“添加新项”对话框中,输入类文件的名称,然后单击“添加”。 (在媒体传输控件示例中,类命名为 CustomMediaTransportControls.)
  2. 修改类代码以派生自 MediaTransportControls 类。
public sealed class CustomMediaTransportControls : MediaTransportControls
{
}
  1. MediaTransportControls 的默认样式 复制到项目的 ResourceDictionary 中。 这是你修改的样式和模板。 (在媒体传输控件示例中,将创建一个名为“主题”的新文件夹,并将名为 generic.xaml 的 ResourceDictionary 文件添加到其中。
  2. 将样式的 TargetType 更改为新的自定义控件类型。 (在示例中,TargetType 更改为 local:CustomMediaTransportControls.)
xmlns:local="using:CustomMediaTransportControls">
...
<Style TargetType="local:CustomMediaTransportControls">
  1. 设置自定义类的 DefaultStyleKey。 这表明你的自定义类要使用一个 TargetType 为 local:CustomMediaTransportControls的样式。
public sealed class CustomMediaTransportControls : MediaTransportControls
{
    public CustomMediaTransportControls()
    {
        this.DefaultStyleKey = typeof(CustomMediaTransportControls);
    }
}
  1. 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 控件模板。

将命令移动到溢出菜单:

  1. 在控件模板中,找到名为 MediaControlsCommandBar 的 CommandBar 元素。
  2. 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="&#xEC57;"/>
      </AppBarButton.Icon>
    </AppBarButton>
...
  </CommandBar.PrimaryCommands>
<!-- Add secondary commands (overflow menu) here -->
  <CommandBar.SecondaryCommands>
    ...
  </CommandBar.SecondaryCommands>
</CommandBar>
  1. 若要使用命令填充菜单,请将所需 AppBarButton 对象的 XAML 从 PrimaryCommands 剪切并粘贴到 SecondaryCommands。 在此示例中,我们将 PlaybackRateButton 移动到溢出菜单。

  2. 将标签添加到按钮并删除样式信息,如下所示。 由于溢出菜单由文本按钮组成,因此必须将文本标签添加到按钮,并删除设置按钮高度和宽度的样式。 否则,它不会在溢出菜单中正确显示。

<CommandBar.SecondaryCommands>
    <AppBarButton x:Name='PlaybackRateButton'
                  Label='Playback Rate'>
    </AppBarButton>
</CommandBar.SecondaryCommands>

重要

你仍必须使按钮可见并启用它,才能在溢出菜单中使用它。 在此示例中,除非 IsPlaybackRateButtonVisible 属性为 true,否则 PlaybackRateButton 元素在溢出菜单中不可见。 除非 IsPlaybackRateEnabled 属性为 true,否则不会启用它。 关于如何设置这些属性的说明显示在上一部分。

添加自定义按钮

你可能想要自定义 MediaTransportControls 的一个原因是向控件添加自定义命令。 无论是将其添加为主命令还是辅助命令,创建命令按钮和修改其行为的过程都是相同的。 在 媒体传输控件示例中,将“分级”按钮添加到主要命令。

添加自定义命令按钮

  1. 创建 AppBarButton 对象并将其添加到控件模板中的 CommandBar。
<AppBarButton x:Name="LikeButton"
              Icon="Like"
              Style="{StaticResource AppBarButtonStyle}"
              MediaTransportControlsHelper.DropoutOrder="3"
              VerticalAlignment="Center" />

必须将其添加到 CommandBar 的相应位置。 (有关详细信息,请参阅“使用溢出菜单”部分。它在 UI 中的位置取决于按钮在标记中的位置。 例如,如果希望此按钮显示为主命令中的最后一个元素,请在主命令列表的末尾添加它。

还可以自定义按钮的图标。 有关详细信息,请参阅 AppBarButton 参考。

  1. 在重写 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();
    }

    //...
}
  1. 将代码添加到 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 的“搜索”控件由 滑块 元素提供。 你可以自定义它的一种方法是调整搜索操作的颗粒度。

默认查找滑块分为 100 个部分,因此搜寻行为仅限于该多个部分。 您可以通过在 MediaPlayerElement.MediaPlayerMediaOpened 事件处理程序中,从 XAML 可视化树中获取滑块来更改查找滑块的粒度。 此示例演示如何使用 VisualTreeHelper 获取对滑块的引用,然后将滑块的默认步骤频率从 1% 更改为 0.1%(1000 步骤),前提是媒体超过 120 分钟。 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;
  }
}