This article has been localized into Chinese by the community.
如何创建完整的音频/视频播放器
在音频视频播放的最后几章,我决定做一个更完整的示例,利用MediaPlayer / MediaElement类来处理音频和视频。
在前几章播放音频和视频基础上,我们将其中用到的几个控件组合起来,显示到一个WPF媒体播放器上,如下图所示:
但是这只是播放音频是它所展示的状态。一旦载入视频,这个界面里面就会自动展开一块区域来显示视频的内容,如下图所示:
让我来告诉你这个东西是怎样做出来的吧!在这篇文章最后,你能看到完整的源代码,你准备好了吗?
界面
这个接口可以分为三块区域:顶部放置工具条,中间放置视频(如果视频导入的话),下方放置一个状态栏,里面用一个文本控件来显示播放时间,一个Slider来显示和控制播放进度,用一个ProgressBar来显示音量。所有的这些控件在之前的教程已经介绍过,所有我们不会过多的描述它。
注意要将功能包装在单独的函数中,不是直接写在按钮的点击事件上。这样可以很容易地复用一些功能而不用再次添加它,比如说一些主菜单或者右键菜单上具有相同功能的选项。这样也很容易根据当前播放器状态来控制功能的开关。
同时请注意我们已经设置MediaElement控件的Stretch属性为None,Window 窗体的SizeToContentMode属性为WidthAndHeight,这样就能使窗体根据内容保持最小尺寸。
为了显示音量,我们在右下角添加了一个ProgressBar 控件。 它不能让用户控制音量,而只是通过数据绑定的方式反映MediaElement控件上的Volume属性。 我们已经实现了一个小而巧妙的方法,让用户无论如何都能控制音量,更多内容请继续观看。
代码
在后端代码中,我们重复使用了前面的几个例子中的技术。比如说,我们初始化了一个DispatcherTimer,让他每秒响应一次来实时显示播放进度。在响应事件中,我们通过设置Minimum 、Maximum和当前文件已播放Value更新Slider控件。并通过滑块上的ValueChanged事件更新文本标签的时分秒。
滑块控件也允许用户跳到文件的另一部分,只要简单的拖拽"thumb"到另一个位置,我们利用DragStarted 和 DragCompleted来实现这个功能,首先是要设置一个变量userIsDraggingSlider告诉计时器当我们拖拽的时候不要更新Slider;当用户释放鼠标按键时,要跳转到指定位置。
我们使用的四个功能命令都有CanExecute和Executed处理程序,特别是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中创建一个非常强大的媒体播放器并不是那么难! 您可以随意为自己的项目扩展此示例 ,接下来如何实现播放列表的功能呢?