本次的作业是制作一个简单的播放器,功能仅限于播放视频和音频,虽说是简单的播放器,但其中还是有很多细节需要注意的。
问题一:布局
本来这个问题不应该是一个问题了,之前老师讲过的Stackpanel和Grid等对于布局一个播放器来说绰绰有余,但上次上课老师提到的NavigationView令我十分感兴趣,这是一个uwp应用程序中随处可见的一种布局,节省了开发者很多的时间。
所以我就着手于建立这个NavigationView了,首先我看了一下XAML Controls Gallery,然而其中关于NavigationView的内容少的可怜,我在复制代码进工程时还报出了很多错误,其中一项就是版本问题,这个NavigationView太新了,以至于老版本不支持,所以我又新建了一个项目将最低版本控制在秋季创意者,并且删除了例子中很多有关样式的内容,最后总算是在程序中看到了它。
参考:XAML Controls Gallery —— NavigationView
仅仅实现界面并不能干任何事情,这个界面的核心就在于他可以在不同页面间来回切换,那么切换这个功能如何实现呢?我在网络上搜索的时候发现相关的内容较少,只在CSDN上找到了两个讲NavigationView切换页面的博客。
参考:https://blog.csdn.net/xiahn1a/article/details/78935260
参考:https://blog.csdn.net/LoHiauFung/article/details/61414592
其中一篇博客的代码中写道
private void nvAll_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) { //先判断是否选中了setting if (args.IsSettingsInvoked) { contentFrame.Navigate(typeof(SettingsPage)); } else { //选中项的内容 switch (args.InvokedItem) { case "Home": ContentFrame.Navigate(typeof(HomePage)); break; } } }
我在实验的过程中我发现我并不知道args.InvokedItem这个属性的具体值是什么,目前看来是字符串但我不清楚是哪个,最后我在程序中输出结果才看到这个属性其实就是界面上左边不同标签的文本,这也提醒了我很多时候网络上的代码不能拿过来直接使用,需要自己看懂弄懂后才不会出错误。最终我写出的代码是这样的:
private void NV_OnItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) { //title.Text = args.InvokedItem.ToString(); switch (args.InvokedItem) { case "picture": contentFrame.Navigate(typeof(pic)); break; case "music": contentFrame.Navigate(typeof(music)); break; case "video": contentFrame.Navigate(typeof(video)); break; } }
问题二:打开文件
之前的学习中我没有用到文件的相关操作,所以我首先去看了一下官方文档。发现了这样一个类:FileOpenPicker,看到这个类名我就知道我找到了想要的。将代码复制到工程中时还遇到了一点小小的问题,例子中的方法是异步的,所以需要进行一些细微的调整。
参考:https://docs.microsoft.com/en-us/uwp/api/Windows.Storage.Pickers.FileOpenPicker#code-snippet-1
在选取文件后,需要对文件进行一些操作来使其变为媒体源,这一步是通过调用 MediaSource.CreateFromStorageFile 初始化新的 MediaObject。然后通过调用 SetPlaybackSource 方法将媒体源设置为 MediaElement 的播放源。例子中的代码是这样的:
if (file != null) { mediaSource = MediaSource.CreateFromStorageFile(file); mediaElement.SetPlaybackSource(mediaSource); }
这里我就不得不要吐槽一下微软的这个参考样例了,之前口口声声说结果在代码端用了个mediaElement,迷惑性贼强,导致我实践的过程中不得不又重新看了其他文档。如下是一个专门讲mediaplayer的文档,感觉写的比之前的要清晰很多。折腾来折腾去,我总算是明白了,在使用MediaSource打开文件后就可以通过已经初始化的MediaPlayer来播放了,不需要MediaElement,我猜测MediaElement是另一种打开多媒体文件的方式,不过文档把它们混着使用确实令人难以理解。
我的代码:
private async void ButtonBase_OnClickAsync(object sender, RoutedEventArgs e) { FileOpenPicker openPicker = new FileOpenPicker { ViewMode = PickerViewMode.Thumbnail, SuggestedStartLocation = PickerLocationId.PicturesLibrary }; openPicker.FileTypeFilter.Add(".mp3"); openPicker.FileTypeFilter.Add(".mp4"); StorageFile file = await openPicker.PickSingleFileAsync(); if (file != null) { // Application now has read/write access to the picked file path.Text = file.Path.ToString(); _mediaSource = MediaSource.CreateFromStorageFile(file); //简单访问 _mediaPlayer = new MediaPlayer(); _mediaPlayer.Source = _mediaSource; _mediaPlayer.Play(); MediaPlayerElement.SetMediaPlayer(_mediaPlayer); //高级访问 /*var mediaPlaybackItem = new MediaPlaybackItem(_mediaSource); _mediaPlayer.Source = mediaPlaybackItem;*/ } else { path.Text = "no file"; } }
问题三:播放
在界面中放置好MediaPlayerElement后,需要把它和MediaPlayer连接起来,参照上述文档我们可以看到可以通过调用 SetMediaPlayer,设置绑定元素的 MediaPlayer 实例。代码很简单,这里就不放了,另外,使用这种方式可以直接播放音频和视频,不用担心音频无法播放的问题。最后我利用StorageFile类中的FileType方法将用户选择的文件类型显示在界面上。
另外还有一个小细节,MediaPlayerElement中有一个属性叫AreTransportControlsEnabled,这个在我参考的博客中是被设置为false的,然而我运行测试时发现视频只能播放,没有我们播放器中那些暂停,控制音量等按钮,我猜测是因为这个属性,将其设置为true后就和正常播放器一样了。
程序截图:
但我还有一个不太明白的地方,编写完成后在测试时我发现我的界面有的时候会显示不全,当我拉伸界面时会出现这种情况:
右半部超出原有边界的会看不到,但右上角关闭等按钮依然可以按,很奇怪,不清楚是我的什么配制出了问题。
总结:
在编写这个简单的播放器的过程中,我学到了很多东西,认识到了什么都没有官方文档好用,文档帮助了我很多。我的下一步计划是加入图片功能,并且将音乐和视频分隔开,做一个全能多媒体浏览器。