too young too simple mediaplayer
这是一个简单的播放器,能且只能播放mp3和mp4文件,通过右键菜单选取文件来播放。
https://github.com/lotsofone/HomeWorkPlayer
播放效果
下面分别是播放mp3和mp4的效果。
文件读取
在做这个too-young-too-simple-mediaplayer的时候,遇到的第一个问题就是读取文件的问题。为了避免我随意篡改文件植入病毒盗取密码控制电脑搞DDos攻击,uwp限制了应用对文件的访问,我们无法随意地读取文件。
读取文件的过程异常复杂,首先要用FileOpenPicker去让用户选择文件,然后要得到StorageFile,然后再打开成IRandomAccessStream,最后终于可以把文件传到MediaElement了。
用到的网页有:
https://msdn.microsoft.com/zh-cn/library/windows/apps/xaml/windows.storage.pickers.fileopenpicker.aspx
这个网页没有有价值的代码,我是通过函数返回值找到下一个类,再通过下一个类的返回值一层层找,找到了前文提到的“链条”。
https://docs.microsoft.com/en-us/previous-versions/windows/apps/hh771180(v=win.10)
这个网页提供了如下代码:
FileOpenPicker openPicker = new FileOpenPicker(); openPicker.ViewMode = PickerViewMode.Thumbnail; openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; openPicker.FileTypeFilter.Add(".jpg"); openPicker.FileTypeFilter.Add(".jpeg"); openPicker.FileTypeFilter.Add(".png"); StorageFile file = await openPicker.PickSingleFileAsync(); if (file != null) { // Application now has read/write access to the picked file OutputTextBlock.Text = "Picked photo: " + file.Name; } else { OutputTextBlock.Text = "Operation cancelled."; }
然后我就写出来了:
FileOpenPicker picker = new FileOpenPicker(); picker.ViewMode = PickerViewMode.Thumbnail; picker.FileTypeFilter.Add(".mp4"); picker.FileTypeFilter.Add(".mp3"); StorageFile file = await picker.PickSingleFileAsync(); if (file != null) { var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read); mainplayer.SetSource(stream, file.ContentType); musicpic.Opacity = 100; }
右键菜单
然后是右键菜单打开文件。本来最简单的办法是用一个Button去触发一个事件,然后开启FileOpenPicker,然后去弄上面一长串的东西。然而,加一个Button对这个界面太不友好了,看起来十分不美观。一整片的东西旁边挂一个小按钮,然后还挡住看视频,成何体统,所以就想用右键打开Flyout来选取文件。
比较容易处理的Flyout是Button.Flyout,按一下按钮打开Flyout。但是之前就说了弄个按钮很丑,所以这个方案否决,于是就找到了用FlyoutBase,然后通过右键事件来让这个Flyout弹出来的办法。不过呢,这个办法弹出的Flyout时钟出现在窗体最上方,无法做到在右键处出现Flyout起到右键菜单的效果,所以又是搜啊搜。
终于又找到了另外一种方法,这种方法里面其实MenuFlyout已经独立于这个MediaElement了。它相当于是个Flyout的模板,通过x:Name才能访问到。然后再单独ShowAt在取得的鼠标位置上即可。
实验中还发现,FlyoutBase和MenuFlyout无法指定Name,只能指定x:Name。
用到的网页有:
https://www.cnblogs.com/ansen312/p/5913372.html
这个网页写了代码:
<TextBlock Name="textBlock1" Margin="5" Text="按我弹出 Flyout" Tapped="textBlock1_Tapped" FontSize="18"> <FlyoutBase.AttachedFlyout> <Flyout Placement="Right"> <TextBlock Text="我是 Flyout 中的内容" /> </Flyout> </FlyoutBase.AttachedFlyout> </TextBlock>
然后我猜想FlyoutBase.AttachedFlyout是不是能写在任何东西里面,就试了下放进MediaElement,结果还真可以:
<MediaElement Name="mainplayer" HorizontalAlignment="Left" Height="auto" VerticalAlignment="Top" Width="auto" AutoPlay="True" AreTransportControlsEnabled="True" RightTapped="mainplayer_RightTapped"> <FlyoutBase.AttachedFlyout> <MenuFlyout x:Name="mainmenu"> <MenuFlyoutItem Text="选择文件" Tag="选择文件" Click="Button_ClickAsync"/> </MenuFlyout> </FlyoutBase.AttachedFlyout> </MediaElement>
https://blog.csdn.net/lindexi_gd/article/details/52724410
这个网页里面写了:
private void GridColection_OnRightTapped(object sender, RightTappedRoutedEventArgs e) { MenuFlyout myFlyout = new MenuFlyout(); MenuFlyoutItem firstItem = new MenuFlyoutItem { Text = "OneIt" }; MenuFlyoutItem secondItem = new MenuFlyoutItem { Text = "TwoIt" }; myFlyout.Items.Add(firstItem); myFlyout.Items.Add(secondItem); //if you only want to show in left or buttom //myFlyout.Placement = FlyoutPlacementMode.Left; FrameworkElement senderElement = sender as FrameworkElement; //the code can show the flyout in your mouse click myFlyout.ShowAt(sender as UIElement, e.GetPosition(sender as UIElement)); }
其实就是暗示了我,这个FlyoutBase已经超越了MediaElement的管辖,可以独立出现,然后我就写出了:
mainmenu.ShowAt(sender as UIElement, e.GetPosition(sender as UIElement));
背景切换
播放音频时会出现音乐背景图片,这个就太简单了,没啥好说的。第一次选择文件的时候把图片背景的Opacity设置成100,然后如果MediaElement打开的是视频,边框就会被黑色填满,否则自己就会变透明。