先附上工程地址:http://download.youkuaiyun.com/detail/felicitia/5303422
当年赶出来的windows phone的小程序,这次UID实验又拿出来弄了个报时。。话说之前感觉很喜欢的拖拽现在好讨厌,好在UI已经确定了,只是加上了语音报时的功能。声音不是很连贯,没办法自己录的也没有掐头去尾,效果不是很好,不过silverlight里面使用XNA的东西还是很方便的,都怪自己没有早点试一试啊!下面说说遇到的问题~
1、遇到最大的问题就是之前采用MediaElement,加载了多个声音元素之后出现了非常诡异的事情!应该播放背景音乐“蓝精灵”的时候会播放“叮”,甚至把“叮”的资源改为“蓝精灵”也不行!这时候会播放“分”之类的,总之就是不播放“蓝精灵”。后来根据观察,发现错乱的播放依次是与加载顺序相反的,而“蓝精灵”的加载是第一个,故一直不播放。查了资料发现,MediaElement会在设置资源的sourse属性的时候自动播放,则应该是每加载一个就播放一个,而后面的占用了前面的资源,使得听起来就是最后的那个音乐,造成错乱的效果。一点就到机房了,居然6点10分还没检查!这个大bug我要恨死你啦!
耽误了太久的时间,后来采用了XNA的effect。本来以为silverlight不支持XNA,必须建成XNA的项目,结果引用之后就可以了。但effect的属性很少,没有state,也不好控制。此时play后面的音乐的时候前面的还没有停止,所以造成声音的叠加。
最后采用了effectInstance的实例,根据state来判断。比如:
while (SoundState.Playing == dingInstance.State) ;
即可使该声音播放完在进行接下来的播放。但是由于自己录音的效果不好,首尾都有空白的部分,导致声音不连贯,一个一个去掉过于麻烦,后来又采用了现成休眠的办法。比如:
Thread.Sleep(500); (需要using System.Threading;)
来使声音尽量连贯。
说下effectInstance的使用吧。首先采用effect的话不能控制声音的暂停,获取状态等,适合播放较短的声音。如果创建了实例方法就灵活一些,具体代码如下:
首先引用Microsoft.Xna.Framework
然后using Microsoft.Xna.Framework.Audio;using Microsoft.Xna.Framework;
声明:
Stream stream = null; SoundEffect effect = null; SoundEffectInstance effectInstance = null;
定义:
stream = TitleContainer.OpenStream("Sounds/blue.wav"); FrameworkDispatcher.Update(); effect = SoundEffect.FromStream(stream); effectInstance = effect.CreateInstance();
直接使用实例的方法即可。注意声音必须是wav格式的,并且生成方式是content(内容)。
2、时间选择控件。采用TimePicker。需要引用Microsoft.Phone.Controls和Microsoft.Phone.Controls.Toolkit;
在xaml文件的跟标签中加上属性xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit";
布局中:
<toolkit:TimePicker x:Name="timePicker" Header="时间选择" Height="154" Width="442" FontSize="24" Margin="19,156,19,458" Grid.RowSpan="2" DataContext="{Binding}" />
3、重力感应的加速度传感器的使用,需要using Microsoft.Devices.Sensors;
声明变量:
public Accelerometer accelerometer;
构造函数中:
accelerometer = new Accelerometer(); accelerometer.ReadingChanged += new EventHandler<AccelerometerReadingEventArgs>(AccelerometerDataChanged); accelerometer.Start();
重写函数(各个值是从-1到1,可以打开模拟器模拟,能看到具体的值):
/*判断加速度是否满足条件*/ public void AccelerometerDataChanged(object sender, AccelerometerReadingEventArgs e) { if (e.X < -0.7) { left = 1; } if (left == 1 && e.X > 0.7) { left = 0; count++; } }
4、固定时间触发的函数。
声明定时器:
DispatcherTimer tmrSecond = null;
构造函数中:
tmrSecond = new DispatcherTimer(); tmrSecond.Interval = TimeSpan.FromSeconds(1); tmrSecond.Tick += OnSecondTick; tmrSecond.Start();
在onSecondTick函数中写需要执行的代码:
public void OnSecondTick(object sender, EventArgs args) { textBox1.Text = tmp + DateTime.Now.Second + " 秒 "; /*音量递增*/ if (effectInstance.Volume > 0.9) { effectInstance.Volume = 1f; } if (effectInstance.Volume != 1) { effectInstance.Volume += 0.1f; } if (count > 0) { duration--; count = 0; } /*满足条件的时间达到闹铃的时间*/ if (duration == 0) { PageTitle.Text = "你真棒~!"; image.Source = myImage; effect.Dispose(); tmrSecond.Stop(); var appStorage = IsolatedStorageFile.GetUserStoreForApplication(); string name = "alarm.txt"; using (var file = appStorage.OpenFile(name, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write)) { using (var writer = new StreamWriter(file)) { writer.WriteLine("False"); writer.WriteLine(MainPage.srHour); writer.WriteLine(MainPage.srMinute); writer.WriteLine(MainPage.srDuration); } } } }
5、独立存储,以添加闹钟为例,点击保存时的函数:
private void save_Click(object sender, RoutedEventArgs e) { DateTime time = (DateTime)timePicker.Value; var appStorage = IsolatedStorageFile.GetUserStoreForApplication(); string name = "alarm.txt"; using (var file = appStorage.OpenFile(name, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write)) { using (var writer = new StreamWriter(file)) { writer.WriteLine(switcher.IsChecked); writer.WriteLine(time.Hour.ToString()); writer.WriteLine(time.Minute.ToString()); writer.WriteLine(Math.Ceiling(duration.Value * 10)); } } NavigationService.GoBack(); }
6、导航到其他页面:
7、返回上一页面:private void Setting_Click(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/LazyClock;component/Look.xaml", UriKind.Relative)); }
private void back_Click(object sender, RoutedEventArgs e) { NavigationService.GoBack(); }
程序使用简要说明:
本程序实现了一个简易的闹钟,无法再后台运行,只能设定一次响铃时间内或者修改,删除。但是用独立存储保证二次打开时会记录之前保存的闹钟信息。主界面中可以设置时间,每秒钟会判断是否到达响铃时间,如果到达,则语音报时,之后跳转到响铃的页面。根据设定的时间,需要采用重力感应用力摇晃手机,摇晃到规定的时间声音才会暂停。背景音乐是渐强的。
最后是效果截图: