在上一篇,我们了解了如何在Silverlight的Out of Browser模式下进行Debug调试,另外学习Silverlight OOB应用的一个新特性Notifications窗口。本篇,我们将结合以往的Out of Browser特性,创建一款新的Out of Browser实例, 音乐播放器。 该实例目的比较简单,实现音乐播放,实现音乐文件列表读取,实现音乐文件信息读取,另外音乐播放自动跳转等功能。
在实例开始前,我们仍旧需要了解一些基础知识。Silverlight对音频的支持是使用MediaElement类,该类使用方法非常简单,该类的详细解释,请看MSDN
2 x:Name ="media"
3 Source ="xbox.wmv"
4 CurrentStateChanged ="media_state_changed"
5 Width ="300" Height ="300" />
在了解了音频播放类的简单使用后,让我们先看看项目完成后的效果图,
从上面效果图中可以看出整个实例项目UI分5个部分,
1. 音频控制部分,这部分是实例主要功能;
2. 音频文件信息部分,这部分是获取显示当前和下一首音乐文件信息;
3. 唱片图片信息,其实这部分也是属于音频文件信息,不过这里单独列出来,使用独立的类进行处理;
4. 音频文件列表,该列表是载入My Music目录中的音乐文件,并支持用户选择播放功能;
5. UI控制,该部分可以使播放器进入最小化状态。例如:
下面我们开始分别解释以上几个部分的实例设计方法。
我们仍旧使用SilverlightOOBDemo项目,不过为了使代码更清晰易读,这次不再使用OutofBrowserMainPage作为OOB应用主界面,我们重新创建一个新的OOB应用界面OutofBrowserMusicPlayer。
为了修改启动页面为OutofBrowserMusicPlayer,为此,我们需要修改App.xaml中的启动页面代码:
2 {
3 if ( ! Application.Current.IsRunningOutOfBrowser)
4 {
5 this .RootVisual = new MainPage();
6 }
7 else
8 {
9 // this.RootVisual = new OutofBrowserMainPage();
10 this .RootVisual = new OutofBrowserMusicPlayer();
11 }
12
13 }
根据实例需求,我们最主要的功能就是播放音乐,所以,我们第一步首先实现Out of Browser应用音频控制。
1. 创建自定义音频控制控件;
对于音频控制,这里我们使用了自定义控件控制音乐的播放。AudioControl.xaml控件,
2 < Grid.ColumnDefinitions >
3 < ColumnDefinition Width ="Auto" />
4 < ColumnDefinition Width ="*" />
5 < ColumnDefinition Width ="25" />
6 < ColumnDefinition Width ="Auto" />
7 < ColumnDefinition Width ="Auto" />
8 </ Grid.ColumnDefinitions >
9 < Grid Grid.Column ="0" Margin ="0,0,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Center" x:Name ="gridCol1" >
10 < ToggleButton Cursor ="Hand" Margin ="0,0,0,0" x:Name ="btnPlay" RenderTransformOrigin ="0.5,0.5" Template =" {StaticResource playControlTemplate} " >
11 < ToggleButton.RenderTransform >
12 < TransformGroup >
13 < ScaleTransform ScaleX ="1" ScaleY ="1" />
14 < SkewTransform />
15 < RotateTransform />
16 < TranslateTransform />
17 </ TransformGroup >
18 </ ToggleButton.RenderTransform >
19 </ ToggleButton >
20 </ Grid >
21 < Grid Grid.Column ="1" Margin ="0,0,0,0" HorizontalAlignment ="Stretch" x:Name ="gridCol2" VerticalAlignment ="Center" >
22 < Grid.ColumnDefinitions >
23 < ColumnDefinition Width ="*" />
24 < ColumnDefinition Width ="40" />
25 < ColumnDefinition Width ="10" />
26 < ColumnDefinition Width ="40" />
27 </ Grid.ColumnDefinitions >
28 < TextBlock x:Name ="tbCurrentTime" Margin ="0,1.5,0,0" Height ="12" FontFamily ="Verdana" FontSize ="10" Text ="00:00" TextWrapping ="Wrap" Foreground ="#FFFFFFFF" FontStyle ="Normal" HorizontalAlignment ="Right" TextAlignment ="Right" Grid.Column ="1" />
29 < TextBlock Margin ="0,1.5,0,0" Height ="12" FontFamily ="Verdana" FontSize ="10" Text ="/" TextWrapping ="Wrap" Foreground ="#FFFFFFFF" FontStyle ="Normal" HorizontalAlignment ="Center" TextAlignment ="Right" Grid.Column ="2" />
30 < TextBlock x:Name ="tbTotalTime" Margin ="0,1.5,0,0" Height ="12" FontFamily ="Verdana" FontSize ="10" Text ="00:00" TextWrapping ="Wrap" Foreground ="#FFFFFFFF" FontStyle ="Normal" HorizontalAlignment ="Left" TextAlignment ="Right" Grid.Column ="3" />
31 < local:MediaSlider Margin ="0,1.5,0,0" HorizontalAlignment ="Stretch" Maximum ="100" x:Name ="sliderTimeline" Style =" {StaticResource progressSliderStyle} " Grid.Column ="0" Value ="0" Visibility ="Visible" />
32 </ Grid >
33 < Grid Grid.Column ="2" Margin ="4,0,4,0" HorizontalAlignment ="Stretch" x:Name ="gridCol3" VerticalAlignment ="Center" >
34 < local:Spinner Margin ="0,0,0,0" x:Name ="spinner" Width ="17" Height ="17" HorizontalAlignment ="Center" VerticalAlignment ="Center" />
35 </ Grid >
36 < Grid Grid.Column ="3" Margin ="0,10.30,0,10.30" HorizontalAlignment ="Stretch" x:Name ="gridCol4" Width ="70" VerticalAlignment ="Stretch" d:LayoutOverrides ="Height" >
37 < Grid Margin ="0,0,0,0" HorizontalAlignment ="Right" VerticalAlignment ="Center" Width ="70" >
38 < Grid.ColumnDefinitions >
39 < ColumnDefinition Width ="Auto" />
40 < ColumnDefinition Width ="*" />
41 </ Grid.ColumnDefinitions >
42 < ToggleButton HorizontalAlignment ="Left" IsChecked ="True" Margin ="0,0,0,0" x:Name ="btnSpeaker" Template =" {StaticResource speakerControlTemplate} " />
43 < Slider Grid.Column ="1" HorizontalAlignment ="Stretch" Margin ="3,0,0,0" VerticalAlignment ="Center" Maximum ="1" x:Name ="sliderVolume" Style =" {StaticResource volumeSliderStyle} " Background ="#FF777777" />
44 </ Grid >
45 </ Grid >
46 < Grid Grid.Column ="4" Margin ="0,10.3120002746582,4,10.3120002746582" HorizontalAlignment ="Right" x:Name ="gridCol5" VerticalAlignment ="Stretch" d:LayoutOverrides ="Height" >
47 < ToggleButton Cursor ="Hand" HorizontalAlignment ="Left" Margin ="0,0,0,0" x:Name ="btnFullScreen" Template =" {StaticResource fullScreenControlTemplate} " />
48 </ Grid >
49 </ Grid >
从以上代码可以看到,在AudioControl中有两个自定义控件local:MediaSlider和local:Spinner。
MediaSlider:
其功能是控制音乐播放进度,支持拖拽前进或者后退音乐播放进度。由于篇幅问题,这里不再列出详细代码,大家可以下载后面的源代码项目参考。
而Spinner控件,是一个载入标识,当音频载入时,会显示该控件。该控件为Path绘制的控件,这里不再贴出代码描述。
2. 获取音频文件信息部分
该部分我们同样也创建一个自定义控件来实现,TrackInfo.xaml,主要是负责在客户端显示音频文件的信息,而Silverlight没有相关API可以实现读取音频文件的标签信息,这里,我们需要引入一个微软开源类库TagLib。该类库的主要功能就是读取和修改音乐文件的标签信息。
其调用方法非常简单:
2 tags = TagLib.File.Create(MediaFile.ID);
3 // 设置标签属性
4 MediaFile.Artist = tags.Tag.FirstPerformer;
5 MediaFile.Title = tags.Tag.Title;
6 MediaFile.Album = tags.Tag.Album;
7 MediaFile.Genre = tags.Tag.FirstGenre;
当音乐标签信息获取成功后,即可将信息绑定到TrackInfo.DataContext。
3. 唱片图片信息
对于唱片的图片信息,这里需要读取Image从本地目录,当没有唱片图片时,则显示默认Music.png图片。这里需要注意的是,读取本地文件,需要OOB应用权限信任。
2 {
3 get
4 {
5 BitmapImage image;
6
7 if ( string .IsNullOrEmpty(AlbumArtPath))
8 {
9 if ( null == _default)
10 {
11 _default = new BitmapImage( new Uri( " ../Images/Music.png " , UriKind.Relative));
12 }
13
14 image = _default;
15 }
16 else
17 {
18 FileStream stream = File.Open(AlbumArtPath, FileMode.Open, FileAccess.Read);
19
20 image = new BitmapImage();
21 image.SetSource(stream);
22 stream.Close();
23 }
24
25 return image;
26 }
27 }
4. 获取音频文件列表
从演示图片可以看出,我们的音频文件列表,是用了一个绑定了音乐播放文件信息的Datagrid。
其代码非常简单,创建两列,分别绑定歌手和歌曲名:
2 Grid.Row ="1"
3 Grid.Column ="1"
4 Grid.RowSpan ="3"
5 VerticalAlignment ="Top"
6 Margin ="4"
7 Height ="296"
8 Style =" {StaticResource DataGridStyle} "
9 AutoGenerateColumns ="False"
10 CanUserResizeColumns ="True"
11 CanUserSortColumns ="False"
12 SelectionChanged ="playList_SelectionChanged" >
13 < data:DataGrid.Columns >
14 < data:DataGridTextColumn Header ="歌手"
15 Binding =" {Binding Artist} "
16 FontSize ="12" />
17 < data:DataGridTextColumn Header ="歌名"
18 Binding =" {Binding Title} "
19 FontSize ="12"
20 Width ="*" />
21 </ data:DataGrid.Columns >
22 </ data:DataGrid >
而后台,在读取了My Music目录后,将数据集绑定到datagrid.ItemsSource就可以正常实现歌曲列表了。
2 {
3 List < MediaFile > files = null ; ;
4 MediaFile mf;
5 string path = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
6 IEnumerable < string > list = Directory.EnumerateFiles(path, " *.mp3 " , SearchOption.AllDirectories);
7 TagLib.File tags;
8 files = GetCachedList(list);
9 if ( null == files || files.Count == 0 )
10 {
11 files = new List < MediaFile > ();
12 foreach ( string file in list)
13 {
14 mf = new MediaFile();
15 mf.ID = file;
16 mf.AlbumArtPath = GetAlbumArtPath(file);
17 files.Add(mf);
18 }
19
20 for ( int idx = 0 ; idx < files.Count; idx ++ )
21 {
22 mf = files[idx];
23 tags = TagLib.File.Create(mf.ID);
24 mf.Artist = tags.Tag.FirstPerformer;
25 mf.Title = tags.Tag.Title;
26 mf.Album = tags.Tag.Album;
27 mf.Genre = tags.Tag.FirstGenre;
28 }
29 SaveCachedList(files);
30 }
31
32 return files;
33 }
在绑定成功后,同时,我们支持用户选择指定音乐播放,使用Datagrid的SelectionChanged事件即可。
2 {
3 DataGrid dg = (sender as DataGrid);
4
5 if (dg.SelectedIndex != _nowPlaying)
6 {
7 if (dg.SelectedIndex != 0 )
8 {
9 me.AutoPlay = true ;
10 }
11 OpenAndPlay(dg.SelectedIndex);
12 }
13
14 }
5. UI控制
对于UI的控制,这里我们只是简单的实现了隐藏和显示音乐信息框的功能,其代码实现:
2 {
3 Window main = Application.Current.MainWindow;
4
5 if ( ! _min)
6 {
7 main.Height = 40 ;
8 rot.Angle = 0 ;
9 }
10 else
11 {
12 main.Height = 340 ;
13 rot.Angle = 180 ;
14 }
15
16 _min = ! _min;
17 }
上面是OOB音乐播放器5个部分的核心功能代码,这里,我想同时将上一篇讲到的Notifications窗口应用到实例中,我们可以仍旧使用NotificationControl文件,在其中对播放音乐Title进行绑定,即当音乐播放完毕后,即弹出消息提示播放下一首“XXX”音乐。效果如下图:
根据上一篇介绍Notifications窗口的代码,我们简单进行修改,即可实现本篇实例需求:
2 private void ShowToast()
3 {
4 notifyWindow = new NotificationWindow();
5
6 if (notifyWindow.Visibility == Visibility.Visible)
7 notifyWindow.Close();
8
9 NotificationControl myNotify = new NotificationControl();
10 myNotify.DataContext = _playList[_nowPlaying];
11 notifyWindow.Width = 300 ;
12 notifyWindow.Height = 100 ;
13 notifyWindow.Content = myNotify;
14 notifyWindow.Show( 10000 );
15 }
至此,一款基于Silverlight的Out of Browser模式的音乐播放器基本完成了。大家可以根据该实例添加更多自定义功能,例如添加互联网音乐播放功能,音乐搜索功能等,创建属于自己的Silverlight版酷我音乐盒。
欢迎大家加入"专注Silverlight" 技术讨论群: