Categories: WPF 教程

WPF教程之 如何创建完整的音频/视频播放器

音频与视频:

如何创建完整的音频/视频播放器

在音频视频播放的最后几章,我决定做一个更完整的示例,利用MediaPlayer / MediaElement类来处理音频和视频。

在前几章播放音频和视频基础上,我们将其中用到的几个控件组合起来,显示到一个WPF媒体播放器上,如下图所示:

但是这只是播放音频是它所展示的状态。一旦载入视频,这个界面里面就会自动展开一块区域来显示视频的内容,如下图所示:

让我来告诉你这个东西是怎样做出来的吧!在这篇文章最后,你能看到完整的源代码,你准备好了吗?

界面

这个接口可以分为三块区域:顶部放置工具条,中间放置视频(如果视频导入的话),下方放置一个状态栏,里面用一个文本控件来显示播放时间,一个Slider来显示和控制播放进度,用一个ProgressBar来显示音量。所有的这些控件在之前的教程已经介绍过,所有我们不会过多的描述它。

注意要将功能包装在单独的函数中,不是直接写在按钮的点击事件上。这样可以很容易地复用一些功能而不用再次添加它,比如说一些主菜单或者右键菜单上具有相同功能的选项。这样也很容易根据当前播放器状态来控制功能的开关。

同时请注意我们已经设置MediaElement控件的Stretch属性为None,Window 窗体的SizeToContentMode属性为WidthAndHeight,这样就能使窗体根据内容保持最小尺寸。

为了显示音量,我们在右下角添加了一个ProgressBar 控件。 它不能让用户控制音量,而只是通过数据绑定的方式反映MediaElement控件上的Volume属性。 我们已经实现了一个小而巧妙的方法,让用户无论如何都能控制音量,更多内容请继续观看。

代码

在后端代码中,我们重复使用了前面的几个例子中的技术。比如说,我们初始化了一个DispatcherTimer,让他每秒响应一次来实时显示播放进度。在响应事件中,我们通过设置MinimumMaximum和当前文件已播放Value更新Slider控件。并通过滑块上的ValueChanged事件更新文本标签的时分秒。

滑块控件也允许用户跳到文件的另一部分,只要简单的拖拽”thumb”到另一个位置,我们利用DragStartedDragCompleted来实现这个功能,首先是要设置一个变量userIsDraggingSlider告诉计时器当我们拖拽的时候不要更新Slider;当用户释放鼠标按键时,要跳转到指定位置。

我们使用的四个功能命令都有CanExecuteExecuted处理程序,特别是Pause和Stop的命令很有意思。 由于我们无法从MediaElement控件获取当前状态,因此我们必须自己跟踪当前状态。 这是通过局部变量mediaPlayerIsPlaying完成的,我们会定期检查是否应启用“暂停”和“停止”按钮。

你应该注意的最后一个细节是Grid_MouseWheel事件。 主网格Grid覆盖整个窗口,因此通过此事件,我们会在用户滚动滚轮时收到通知。 当发生这种情况时,作为一个小技巧,我们根据方向上调或下调音量(我们通过查看Delta属性得到它,向下滚动时为负,向上滚动时为正)。 这会立即反映在用户界面中,其中ProgressBar控件绑定到MediaElement的Volume属性。

完整源代码

根据上述所有理论,下面是对应的完整源代码:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.AudioVideoPlayerCompleteSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF Media Player" Height="300" Width="300"
        MinWidth="300" SizeToContent="WidthAndHeight">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Open" CanExecute="Open_CanExecute" Executed="Open_Executed" />
        <CommandBinding Command="MediaCommands.Play" CanExecute="Play_CanExecute" Executed="Play_Executed" />
        <CommandBinding Command="MediaCommands.Pause" CanExecute="Pause_CanExecute" Executed="Pause_Executed" />
        <CommandBinding Command="MediaCommands.Stop" CanExecute="Stop_CanExecute" Executed="Stop_Executed" />
    </Window.CommandBindings>
    <Grid MouseWheel="Grid_MouseWheel">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ToolBar>
            <Button Command="ApplicationCommands.Open">
                <Image Source="/WpfTutorialSamples;component/Images/folder.png" />
            </Button>
            <Separator />
            <Button Command="MediaCommands.Play">
                <Image Source="/WpfTutorialSamples;component/Images/control_play_blue.png" />
            </Button>
            <Button Command="MediaCommands.Pause">
                <Image Source="/WpfTutorialSamples;component/Images/control_pause_blue.png" />
            </Button>
            <Button Command="MediaCommands.Stop">
                <Image Source="/WpfTutorialSamples;component/Images/control_stop_blue.png" />
            </Button>
        </ToolBar>

        <MediaElement Name="mePlayer" Grid.Row="1" LoadedBehavior="Manual" Stretch="None" />

        <StatusBar Grid.Row="2">
            <StatusBar.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </StatusBar.ItemsPanel>
            <StatusBarItem>
                <TextBlock Name="lblProgressStatus">00:00:00</TextBlock>
            </StatusBarItem>
            <StatusBarItem Grid.Column="1" HorizontalContentAlignment="Stretch">
                <Slider Name="sliProgress" Thumb.DragStarted="sliProgress_DragStarted"  Thumb.DragCompleted="sliProgress_DragCompleted" ValueChanged="sliProgress_ValueChanged" />
            </StatusBarItem>
            <StatusBarItem Grid.Column="2">
                <ProgressBar Name="pbVolume" Width="50" Height="12" Maximum="1" Value="{Binding ElementName=mePlayer, Path=Volume}" />
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;
using Microsoft.Win32;

namespace WpfTutorialSamples.Audio_and_Video
{
 public partial class AudioVideoPlayerCompleteSample : Window
 {
  private bool mediaPlayerIsPlaying = false;
  private bool userIsDraggingSlider = false;

  public AudioVideoPlayerCompleteSample()
  {
   InitializeComponent();

   DispatcherTimer timer = new DispatcherTimer();
   timer.Interval = TimeSpan.FromSeconds(1);
   timer.Tick += timer_Tick;
   timer.Start();
  }

  private void timer_Tick(object sender, EventArgs e)
  {
   if((mePlayer.Source != null) && (mePlayer.NaturalDuration.HasTimeSpan) && (!userIsDraggingSlider))
   {
    sliProgress.Minimum = 0;
    sliProgress.Maximum = mePlayer.NaturalDuration.TimeSpan.TotalSeconds;
    sliProgress.Value = mePlayer.Position.TotalSeconds;
   }
  }

  private void Open_CanExecute(object sender, CanExecuteRoutedEventArgs e)
  {
   e.CanExecute = true;
  }

  private void Open_Executed(object sender, ExecutedRoutedEventArgs e)
  {
   OpenFileDialog openFileDialog = new OpenFileDialog();
   openFileDialog.Filter = "Media files (*.mp3;*.mpg;*.mpeg)|*.mp3;*.mpg;*.mpeg|All files (*.*)|*.*";
   if(openFileDialog.ShowDialog() == true)
    mePlayer.Source = new Uri(openFileDialog.FileName);
  }

  private void Play_CanExecute(object sender, CanExecuteRoutedEventArgs e)
  {
   e.CanExecute = (mePlayer != null) && (mePlayer.Source != null);
  }

  private void Play_Executed(object sender, ExecutedRoutedEventArgs e)
  {
   mePlayer.Play();
   mediaPlayerIsPlaying = true;
  }

  private void Pause_CanExecute(object sender, CanExecuteRoutedEventArgs e)
  {
   e.CanExecute = mediaPlayerIsPlaying;
  }

  private void Pause_Executed(object sender, ExecutedRoutedEventArgs e)
  {
   mePlayer.Pause();
  }

  private void Stop_CanExecute(object sender, CanExecuteRoutedEventArgs e)
  {
   e.CanExecute = mediaPlayerIsPlaying;
  }

  private void Stop_Executed(object sender, ExecutedRoutedEventArgs e)
  {
   mePlayer.Stop();
   mediaPlayerIsPlaying = false;
  }

  private void sliProgress_DragStarted(object sender, DragStartedEventArgs e)
  {
   userIsDraggingSlider = true;
  }

  private void sliProgress_DragCompleted(object sender, DragCompletedEventArgs e)
  {
   userIsDraggingSlider = false;
   mePlayer.Position = TimeSpan.FromSeconds(sliProgress.Value);
  }

  private void sliProgress_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
  {
   lblProgressStatus.Text = TimeSpan.FromSeconds(sliProgress.Value).ToString(@"hh:mm:ss");
  }

  private void Grid_MouseWheel(object sender, MouseWheelEventArgs e)
  {
   mePlayer.Volume += (e.Delta > 0) ? 0.1 : -0.1;
  }

 }
}

小结

代码清单可能看起来有点压抑,但正如您所看到的,其中有很多重复。 如果你把它从图片中拿出来,你很快就会意识到在WPF中创建一个非常强大的媒体播放器并不是那么难! 您可以随意为自己的项目扩展此示例 ,接下来如何实现播放列表的功能呢?

terry

这个人很懒,什么都没有留下~

Share
Published by
terry

Recent Posts

vue:页面注入js修改input值

一般会直接这样写: let z…

10 小时 ago

聊聊vue3中的defineProps

在Vue 3中,defineP…

1 周 ago

在 Chrome 中删除、允许和管理 Cookie

您可以选择删除现有 Cooki…

2 周 ago

自定义指令:聊聊vue中的自定义指令应用法则

今天我们来聊聊vue中的自定义…

3 周 ago

聊聊Vue中@click.stop和@click.prevent

一起来学下聊聊Vue中@cli…

4 周 ago

Nginx 基本操作:启动、停止、重启命令。

我们来学习Nginx基础操作:…

1 月 ago