- 浏览: 109104 次
- 性别:
- 来自: 昆明
文章分类
- 全部博客 (151)
- 120D02 (5)
- 直升机 (1)
- 我的技术资料收集 (82)
- 的技术资料收集 (4)
- .NET Solution (2)
- ASP.NET (1)
- Linq to sql (1)
- 数据库技术(MS SQL) (2)
- 架构/设计 (1)
- 敏捷/持续集成 (1)
- C#.NET开发 (1)
- Matlab开发 (1)
- WinForm开发 (1)
- 开源技术 (1)
- jQuery (1)
- 我的博文 (4)
- js (2)
- android (2)
- 9. 读书笔记 (1)
- CSS3 (1)
- HTML5 (1)
- JavaScript (5)
- 移动开发 (2)
- 编程心得 (1)
- Linux操作系统 (1)
- (BI)商业智能 (1)
- IOS (1)
- Windows Phone (2)
- C# API (1)
- JQuery系列 (1)
- TFS (1)
- C# (2)
- ExtJs (1)
- .NET (1)
- Nginx (1)
- WCF学习笔记 (1)
- Computer Graphic (1)
- IT产品 (1)
- 工具分享 (1)
- MySelf (1)
- C#专栏 (1)
- 管理 (1)
- 基于Oracle Logminer数据同步 (1)
- 日常 (1)
- 实用工具 (1)
- 网页设计 (1)
- avalon (1)
- flash (1)
- DDD (1)
- 01 技术Android (1)
- WCF (1)
- selenium (1)
最新评论
-
464410531:
三国杀。。。。。。。。。。。。。。。。。。。。。。。。。。。。 ...
实用的职场宝典:不提拔你,就因为你只想把工作做好
Windows phone 8 是一个单任务操作系统,任何时候都只有一个应用处于活跃状态,这里的多任务是指对后台任务的支持。本节我们先讲讲应用程序的运行状态,然后看看支持的后台任务,包括:后台代理、后台音频、后台文件传输、后台辅助线程等。
快速导航:
一、应用的状态
二、后台代理
三、后台音频
四、后台文件传输
五、后台辅助线程
一、应用的状态
1)应用的运行状态
我们通过图解来分析应用的运行状态,启动并置于前台界面的应用是唯一处于运行状态的,其他的操作,比如win键,后退导出应用,打开选择器和启动器时都会让当前运行的应用进入休眠状态,如果系统内存不足,处于休眠状态的应用可能会被系统逻辑删除。下面的图示演示了这个过程。
2)如何恢复状态
当应用处于休眠状态时,它的状态信息仍然保留在内存中,用户下次切换进去后不会有任何变化。但是当应用被逻辑删除后,这些状态信息就会丢失,比如表单填写的内容都会消失,为了避免这种情况,我们需要手动保留状态信息。
首先,我们在mainpage定义一些页面表单控件:
[XAML]
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox Text="{Binding TextBox1Text, Mode=TwoWay}" Height="72"
HorizontalAlignment="Left" Margin="20,20,0,0" Name="textBox1"
VerticalAlignment="Top" Width="440" />
<CheckBox IsChecked="{Binding CheckBox1IsChecked, Mode=TwoWay}"
Content="CheckBox" Height="71" Name="checkBox1" Margin="20,100,0,0"
VerticalAlignment="Top"/>
<Slider Value="{Binding Slider1Value, Mode=TwoWay}" Height="84" Name="slider1"
Width="440" Margin="20,180,0,0" VerticalAlignment="Top"/>
<RadioButton IsChecked="{Binding RadioButton1IsChecked, Mode=TwoWay}"
Content="RadioButton 1" Height="71" Name="radioButton1"
GroupName="RadioButtonGroup" Margin="20,260,0,0" VerticalAlignment="Top"/>
<RadioButton IsChecked="{Binding RadioButton1IsChecked, Mode=TwoWay}"
Content="RadioButton 2" Height="71" Name="radioButton2"
GroupName="RadioButtonGroup" Margin="20,340,0,0" VerticalAlignment="Top"/>
</Grid>
我们需要实现在应用逻辑删除后能将其状态保持到页面的State字典中,但是需要我们的数据源支持序列化,所以我们定义与表单关联的ViewModel如下:
[C#]
[DataContract]
public class ViewModel : INotifyPropertyChanged
{
private string _textBox1Text;
private bool _checkBox1IsChecked;
private bool _radioButton1IsChecked;
private bool _radioButton2IsChecked;
private double _slider1Value;
[DataMember]
public string TextBox1Text
{
get { return _textBox1Text; }
set
{
_textBox1Text = value;
NotifyPropertyChanged("TextBox1Text");
}
}
[DataMember]
public bool CheckBox1IsChecked
{
get { return _checkBox1IsChecked; }
set
{
_checkBox1IsChecked = value;
NotifyPropertyChanged("CheckBox1IsChecked");
}
}
[DataMember]
public double Slider1Value
{
get { return _slider1Value; }
set
{
_slider1Value = value;
NotifyPropertyChanged("Slider1Value");
}
}
[DataMember]
public bool RadioButton1IsChecked
{
get { return _radioButton1IsChecked; }
set
{
_radioButton1IsChecked = value;
NotifyPropertyChanged("RadioButton1IsChecked");
}
}
[DataMember]
public bool RadioButton2IsChecked
{
get { return _radioButton2IsChecked; }
set
{
_radioButton2IsChecked = value;
NotifyPropertyChanged("RadioButton2IsChecked");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
我需要对mainpage代码添加页面导航入、导航出的事件。导航出页面的时候,如果不是向后导航,则存储状态。导航入的时候,我们需要判断页面是否为逻辑删除后正在恢复的状态,如果是,则通过状态字典恢复状态。mainpage代码如下:
[C#]
public partial class MainPage : PhoneApplicationPage
{
// 构造函数
public MainPage()
{
InitializeComponent();
_isNewPageInstance = true;
}
ViewModel _viewModel = null;
/// <summary>
/// 新实例还是现有实例
/// </summary>
bool _isNewPageInstance = false;
private void Button_Click_1(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Page1.xaml", UriKind.Relative));
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
//如果不是向后导航,则保存状态
if (e.NavigationMode != System.Windows.Navigation.NavigationMode.Back)
{
State["ViewModel"] = _viewModel;
}
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (_isNewPageInstance)
{
if (_viewModel == null)
{
if (State.Count > 0)
{
_viewModel = (ViewModel)State["ViewModel"];
}
else
{
_viewModel = new ViewModel();
}
}
DataContext = _viewModel;
}
_isNewPageInstance = false;
}
}
然后我们添加一page1页面,该页添加一个返回按钮。用于测试。为了达到调试时即时进入逻辑删除的效果,我们需要设置下。右键项目文件,点属性,在调试选项卡勾选“在调试期间取消激活时逻辑删除”。
二、后台代理
后台代理可以在应用退出以后独立在系统后台运行,它包含两种类型的代理,分别是定期代理和资源密集型代理,前者用于频繁执行小任务,后者用于在系统空闲时执行耗时大任务。要使用后台代理,我们需要添加一个名为Windows phone 计划任务代理的项目,并在应用的项目中添加对其的引用,现在我们要实现在后台代理中弹出Toast,我们需要如下修改ScheduledAgent.cs的OnInvoke方法,代码如下
[C#]
protected override void OnInvoke(ScheduledTask task)
{
string toastMessage = "";
if (task is PeriodicTask)
{
toastMessage = "定期代理正在运行";
}
else
{
toastMessage = "资源密集型代理正在运行";
}
// 用于向用户显示Toast,如果当前任务的前台正在运行,则不显示
ShellToast toast = new ShellToast();
toast.Title = "标题";
toast.Content = toastMessage;
toast.Show();
// 在调试的时候需要及时执行查看效果
#if DEBUG_AGENT
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(15));
#endif
NotifyComplete();
}
接着,我们在应用项目的mainpage中调用代理,代码如下:
[XAML]
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<StackPanel Orientation="Vertical" Name="PeriodicStackPanel" Margin="0,0,0,40">
<TextBlock Text="定期代理" Style="{StaticResource PhoneTextTitle2Style}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="名称: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding Name}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="是否可用" VerticalAlignment="Center" Style="{StaticResource PhoneTextAccentStyle}"/>
<CheckBox Name="PeriodicCheckBox" IsChecked="{Binding IsEnabled}" Checked="PeriodicCheckBox_Checked" Unchecked="PeriodicCheckBox_Unchecked"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="是否已计划: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding IsScheduled}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="上次计划运行时间: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding LastScheduledTime}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="计划结束时间: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding ExpirationTime}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="上一次代理运行退出的原因: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding LastExitReason}" />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Name="ResourceIntensiveStackPanel" Margin="0,0,0,40">
<TextBlock Text="资源密集型代理" Style="{StaticResource PhoneTextTitle2Style}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="名称: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding Name}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="是否可用" VerticalAlignment="Center" Style="{StaticResource PhoneTextAccentStyle}"/>
<CheckBox Name="ResourceIntensiveCheckBox" IsChecked="{Binding IsEnabled}" Checked="ResourceIntensiveCheckBox_Checked" Unchecked="ResourceIntensiveCheckBox_Unchecked"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="是否已计划: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding IsScheduled}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="上次计划运行时间: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding LastScheduledTime}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="计划结束时间: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding ExpirationTime}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="上一次代理运行退出的原因: " Style="{StaticResource PhoneTextAccentStyle}"/>
<TextBlock Text="{Binding LastExitReason}" />
</StackPanel>
</StackPanel>
</StackPanel>
</Grid>
[C#]
public partial class MainPage : PhoneApplicationPage
{
/// <summary>
/// 定期代理
/// </summary>
PeriodicTask periodicTask;
/// <summary>
/// 资源密集型代理
/// </summary>
ResourceIntensiveTask resourceIntensiveTask;
string periodicTaskName = "PeriodicAgent";
string resourceIntensiveTaskName = "ResourceIntensiveAgent";
public bool agentsAreEnabled = true;
// 构造函数
public MainPage()
{
InitializeComponent();
}
//启动定期代理
private void StartPeriodicAgent()
{
agentsAreEnabled = true;
// 获取当前名称的定期代理,如果存在则移除
periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;
if (periodicTask != null)
{
RemoveAgent(periodicTaskName);
}
periodicTask = new PeriodicTask(periodicTaskName);
periodicTask.Description = "这是一个定期代理的描述信息。";
try
{
ScheduledActionService.Add(periodicTask);
PeriodicStackPanel.DataContext = periodicTask;
//在调试的时候需要及时执行查看效果
#if(DEBUG_AGENT)
ScheduledActionService.LaunchForTest(periodicTaskName, TimeSpan.FromSeconds(60));
#endif
}
catch (InvalidOperationException exception)
{
if (exception.Message.Contains("BNS Error: The action is disabled"))
{
MessageBox.Show("本应用的后台计划被用户禁用。");
agentsAreEnabled = false;
PeriodicCheckBox.IsChecked = false;
}
if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
{
MessageBox.Show("定期代理数量达到最大限制。");
}
PeriodicCheckBox.IsChecked = false;
}
catch (SchedulerServiceException)
{
PeriodicCheckBox.IsChecked = false;
}
}
private void StartResourceIntensiveAgent()
{
agentsAreEnabled = true;
// 获取当前名称的资源密集型代理,如果存在则移除
resourceIntensiveTask = ScheduledActionService.Find(resourceIntensiveTaskName) as ResourceIntensiveTask;
if (resourceIntensiveTask != null)
{
RemoveAgent(resourceIntensiveTaskName);
}
resourceIntensiveTask = new ResourceIntensiveTask(resourceIntensiveTaskName);
resourceIntensiveTask.Description = "这是一个资源密集型代理的描述信息。";
try
{
ScheduledActionService.Add(resourceIntensiveTask);
ResourceIntensiveStackPanel.DataContext = resourceIntensiveTask;
//在调试的时候需要及时执行查看效果
#if(DEBUG_AGENT)
ScheduledActionService.LaunchForTest(resourceIntensiveTaskName, TimeSpan.FromSeconds(15));
#endif
}
catch (InvalidOperationException exception)
{
if (exception.Message.Contains("BNS Error: The action is disabled"))
{
MessageBox.Show("本应用的后台计划被用户禁用。");
agentsAreEnabled = false;
}
ResourceIntensiveCheckBox.IsChecked = false;
}
catch (SchedulerServiceException)
{
ResourceIntensiveCheckBox.IsChecked = false;
}
}
bool ignoreCheckBoxEvents = false;
private void PeriodicCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (ignoreCheckBoxEvents)
return;
StartPeriodicAgent();
}
private void PeriodicCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
if (ignoreCheckBoxEvents)
return;
RemoveAgent(periodicTaskName);
}
private void ResourceIntensiveCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (ignoreCheckBoxEvents)
return;
StartResourceIntensiveAgent();
}
private void ResourceIntensiveCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
if (ignoreCheckBoxEvents)
return;
RemoveAgent(resourceIntensiveTaskName);
}
/// <summary>
/// 删除代理
/// </summary>
private void RemoveAgent(string name)
{
try
{
ScheduledActionService.Remove(name);
}
catch (Exception)
{
}
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
ignoreCheckBoxEvents = true;
periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;
if (periodicTask != null)
{
PeriodicStackPanel.DataContext = periodicTask;
}
resourceIntensiveTask = ScheduledActionService.Find(resourceIntensiveTaskName) as ResourceIntensiveTask;
if (resourceIntensiveTask != null)
{
ResourceIntensiveStackPanel.DataContext = resourceIntensiveTask;
}
ignoreCheckBoxEvents = false;
}
}
三、后台音频
通过后台音频的功能我们可以实现在系统后台播放音乐的功能,由于后台音频代理只能访问本地文件夹,所以我们务必要先把需要播放的音乐文件拷贝到本地文件夹中。本示例是把安装文件夹的音频文件拷贝到本地文件夹,代码如下:
[C#]
//把安装文件夹下的文件拷贝到本地文件夹
private void CopyToIsolatedStorage()
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
string[] files = new string[] { "Ring01.wma", "Ring02.wma", "Ring03.wma" };
foreach (var _fileName in files)
{
if (!storage.FileExists(_fileName))
{
string _filePath = "Audio/" + _fileName;
StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));
using (IsolatedStorageFileStream file = storage.CreateFile(_fileName))
{
int chunkSize = 4096;
byte[] bytes = new byte[chunkSize];
int byteCount;
while ((byteCount = resource.Stream.Read(bytes, 0, chunkSize)) > 0)
{
file.Write(bytes, 0, byteCount);
}
}
}
}
string[] icons = new string[] { "Ring01.jpg", "Ring02.jpg", "Ring03.jpg" };
foreach (var _fileName in icons)
{
if (!storage.FileExists(_fileName))
{
string _filePath = "Images/" + _fileName;
StreamResourceInfo iconResource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));
using (IsolatedStorageFileStream file = storage.CreateFile( _fileName))
{
int chunkSize = 4096;
byte[] bytes = new byte[chunkSize];
int byteCount;
while ((byteCount = iconResource.Stream.Read(bytes, 0, chunkSize)) > 0)
{
file.Write(bytes, 0, byteCount);
}
}
}
}
}
}
我们需要在解决方案中添加Windows phone 音频播放代理项目,并在应用项目中添加对其的引用。修改AudioPlayer.cs代码如下:
[C#]
public class AudioPlayer : AudioPlayerAgent
{
private static volatile bool _classInitialized;
private static List<AudioTrack> _playList = new List<AudioTrack>
{
new AudioTrack(new Uri("Ring01.wma", UriKind.Relative),"曲目1","艺术家1","专辑1",new Uri("Ring01.jpg", UriKind.Relative)),
new AudioTrack(new Uri("Ring02.wma", UriKind.Relative),"曲目2","艺术家2","专辑2",new Uri("Ring02.jpg", UriKind.Relative)),
new AudioTrack(new Uri("Ring03.wma", UriKind.Relative),"曲目3","艺术家3","专辑3",new Uri("Ring03.jpg", UriKind.Relative))
};
/// <summary>
/// 当前播放位置
/// </summary>
static int currentTrackNumber = 0;
/// <remarks>
/// AudioPlayer 实例可共享同一进程。
/// 静态字段可用于在 AudioPlayer 实例之间共享状态
/// 或与音频流代理通信。
/// </remarks>
public AudioPlayer()
{
if (!_classInitialized)
{
_classInitialized = true;
// 订阅托管异常处理程序
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
Application.Current.UnhandledException += AudioPlayer_UnhandledException;
});
}
}
/// 出现未处理的异常时执行的代码
private void AudioPlayer_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// 出现未处理的异常;强行进入调试器
System.Diagnostics.Debugger.Break();
}
}
/// <summary>
/// playstate 更改时调用,但 Error 状态除外(参见 OnError)
/// </summary>
/// <param name="player">BackgroundAudioPlayer</param>
/// <param name="track">在 playstate 更改时播放的曲目</param>
/// <param name="playState">播放机的新 playstate </param>
/// <remarks>
/// 无法取消播放状态更改。即使应用程序
/// 导致状态自行更改,假定应用程序已经选择了回调。
///
/// 值得注意的 playstate 事件
/// (a) TrackEnded: 播放器没有当前曲目时激活。代理可设置下一曲目。
/// (b) TrackReady: 音轨已设置完毕,现在可以播放。
///
/// 只在代理请求完成之后调用一次 NotifyComplete(),包括异步回调。
/// </remarks>
protected override void OnPlayStateChanged(BackgroundAudioPlayer player, AudioTrack track, PlayState playState)
{
switch (playState)
{
case PlayState.TrackEnded:
player.Track = GetPreviousTrack();
break;
case PlayState.TrackReady:
player.Play();
break;
case PlayState.Shutdown:
// TODO: 在此处理关机状态(例如保存状态)
break;
case PlayState.Unknown:
break;
case PlayState.Stopped:
break;
case PlayState.Paused:
break;
case PlayState.Playing:
break;
case PlayState.BufferingStarted:
break;
case PlayState.BufferingStopped:
break;
case PlayState.Rewinding:
break;
case PlayState.FastForwarding:
break;
}
NotifyComplete();
}
/// <summary>
/// 在用户使用应用程序/系统提供的用户界面请求操作时调用
/// </summary>
/// <param name="player">BackgroundAudioPlayer</param>
/// <param name="track">用户操作期间播放的曲目</param>
/// <param name="action">用户请求的操作</param>
/// <param name="param">与请求的操作相关联的数据。
/// 在当前版本中,此参数仅适合与 Seek 操作一起使用,
/// 以指明请求的乐曲的位置</param>
/// <remarks>
/// 用户操作不自动对系统状态进行任何更改;如果用户操作受支持,
/// 执行用户操作(如果这些操作受支持)。
///
/// 只在代理请求完成之后调用一次 NotifyComplete(),包括异步回调。
/// </remarks>
protected override void OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param)
{
switch (action)
{
case UserAction.Play:
if (player.PlayerState != PlayState.Playing)
{
player.Play();
}
break;
case UserAction.Stop:
player.Stop();
break;
case UserAction.Pause:
player.Pause();
break;
case UserAction.FastForward:
player.FastForward();
break;
case UserAction.Rewind:
player.Rewind();
break;
case UserAction.Seek:
player.Position = (TimeSpan)param;
break;
case UserAction.SkipNext:
player.Track = GetNextTrack();
break;
case UserAction.SkipPrevious:
AudioTrack previousTrack = GetPreviousTrack();
if (previousTrack != null)
{
player.Track = previousTrack;
}
break;
}
NotifyComplete();
}
/// <summary>
/// 实现逻辑以获取下一个 AudioTrack 实例。
/// 在播放列表中,源可以是文件、Web 请求,等等。
/// </summary>
/// <remarks>
/// AudioTrack URI 确定源,它可以是:
/// (a) 独立存储器文件(相对 URI,表示独立存储器中的路径)
/// (b) HTTP URL(绝对 URI)
/// (c) MediaStreamSource (null)
/// </remarks>
/// <returns>AudioTrack 实例,或如果播放完毕,则返回 null</returns>
private AudioTrack GetNextTrack()
{
// TODO: 添加逻辑以获取下一条音轨
if (++currentTrackNumber >= _playList.Count) currentTrackNumber = 0;
AudioTrack track = _playList[currentTrackNumber];
// 指定曲目
return track;
}
/// <summary>
/// 实现逻辑以获取前一个 AudioTrack 实例。
/// </summary>
/// <remarks>
/// AudioTrack URI 确定源,它可以是:
/// (a) 独立存储器文件(相对 URI,表示独立存储器中的路径)
/// (b) HTTP URL(绝对 URI)
/// (c) MediaStreamSource (null)
/// </remarks>
/// <returns>AudioTrack 实例,或如果不允许前一曲目,则返回 null</returns>
private AudioTrack GetPreviousTrack()
{
// TODO: 添加逻辑以获取前一条音轨
if (--currentTrackNumber < 0) currentTrackNumber = _playList.Count - 1;
AudioTrack track = _playList[currentTrackNumber];
// 指定曲目
return track;
}
/// <summary>
/// 每次播放出错(如 AudioTrack 未正确下载)时调用
/// </summary>
/// <param name="player">BackgroundAudioPlayer</param>
/// <param name="track">出现错误的曲目</param>
/// <param name="error">出现的错误</param>
/// <param name="isFatal">如果为 true,则播放不能继续并且曲目播放将停止</param>
/// <remarks>
/// 不保证在所有情况下都调用此方法。例如,如果后台代理程序
/// 本身具有未处理的异常,则不会回调它来处理它自己的错误。
/// </remarks>
protected override void OnError(BackgroundAudioPlayer player, AudioTrack track, Exception error, bool isFatal)
{
if (isFatal)
{
Abort();
}
else
{
NotifyComplete();
}
}
/// <summary>
/// 取消代理请求时调用
/// </summary>
/// <remarks>
/// 取消请求后,代理需要 5 秒钟完成其工作,
/// 通过调用 NotifyComplete()/Abort()。
/// </remarks>
protected override void OnCancel()
{
}
}
最后,我们在mainpage中添加对播放的控制。
[XAML]
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel 包含应用程序的名称和页标题-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="后台音频" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<!--ContentPanel - 在此处放置其他内容-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Button x:Name="button2" Content="〈" HorizontalAlignment="Left" Margin="13,10,0,0" VerticalAlignment="Top" Click="Button_Click_2"/>
<Button x:Name="button1" Content="▶" HorizontalAlignment="Left" Margin="75,10,0,0" VerticalAlignment="Top" Click="Button_Click_1"/>
<Button x:Name="button3" Content="〉" HorizontalAlignment="Left" Margin="136,10,0,0" VerticalAlignment="Top" Click="Button_Click_3" />
<TextBlock x:Name="textblock1" HorizontalAlignment="Left" Margin="22,87,0,0" TextWrapping="Wrap" VerticalAlignment="Top"/>
<Image x:Name="imge1" HorizontalAlignment="Left" Height="100" Margin="22,142,0,0" VerticalAlignment="Top" Width="100"/>
</Grid>
</Grid>
[C#]
public partial class MainPage : PhoneApplicationPage
{
// 构造函数
public MainPage()
{
InitializeComponent();
BackgroundAudioPlayer.Instance.PlayStateChanged += new EventHandler(Instance_PlayStateChanged);
}
//刚加载时确定播放状态
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
{
button1.Content = "■";
textblock1.Text = "曲目:" + BackgroundAudioPlayer.Instance.Track.Title
+ " 艺术家:" + BackgroundAudioPlayer.Instance.Track.Artist
+ " 专辑:" + BackgroundAudioPlayer.Instance.Track.Album
+ " 曲目长度:" +BackgroundAudioPlayer.Instance.Track.Duration.Minutes + ":" + BackgroundAudioPlayer.Instance.Track.Duration.Seconds;
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
var stream = storage.OpenFile(BackgroundAudioPlayer.Instance.Track.AlbumArt.OriginalString, System.IO.FileMode.Open);
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
imge1.Source = bitmapImage;
stream.Close();
}
}
else
{
button1.Content = "▶";
textblock1.Text = "未播放曲目";
}
}
void Instance_PlayStateChanged(object sender, EventArgs e)
{
switch (BackgroundAudioPlayer.Instance.PlayerState)
{
case PlayState.Playing:
button1.Content = "■";
button2.IsEnabled = true;
button3.IsEnabled = true;
break;
case PlayState.Paused:
case PlayState.Stopped:
button1.Content = "▶";
break;
}
if (null != BackgroundAudioPlayer.Instance.Track && BackgroundAudioPlayer.Instance.PlayerState!= PlayState.Stopped)
{
textblock1.Text = "曲目:" + BackgroundAudioPlayer.Instance.Track.Title
+ " 艺术家:" + BackgroundAudioPlayer.Instance.Track.Artist
+ " 专辑:" + BackgroundAudioPlayer.Instance.Track.Album
+ " 曲目长度:" + BackgroundAudioPlayer.Instance.Track.Duration.Minutes + ":" + BackgroundAudioPlayer.Instance.Track.Duration.Seconds;
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
var stream = storage.OpenFile(BackgroundAudioPlayer.Instance.Track.AlbumArt.OriginalString, System.IO.FileMode.Open);
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
imge1.Source = bitmapImage;
stream.Close();
}
}
}
//播放/暂停
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
BackgroundAudioPlayer.Instance.Pause();
else
BackgroundAudioPlayer.Instance.Play();
}
//向前
private void Button_Click_2(object sender, RoutedEventArgs e)
{
BackgroundAudioPlayer.Instance.SkipPrevious();
button2.IsEnabled = false;
}
//向后
private void Button_Click_3(object sender, RoutedEventArgs e)
{
BackgroundAudioPlayer.Instance.SkipNext();
button3.IsEnabled = false;
}
}
四、后台文件传输
后台文件传输允许我们实现下载上传文件的功能,他限制系统中同时运行的传输任务不能超过两个,并且下载的文件只能存放在本地文件夹的/shared/transfers目录下。下面我们实现一个后台传输任务,下载博客相册中的一张照片。
[XAML]
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel 包含应用程序的名称和页标题-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="后台传输" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<!--ContentPanel - 在此处放置其他内容-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock x:Name="textblock1" HorizontalAlignment="Left" Margin="10,198,0,0" TextWrapping="Wrap" VerticalAlignment="Top"/>
<Button Content="清除传输队列中已完成的任务" HorizontalAlignment="Left" Margin="0,85,0,0" VerticalAlignment="Top" Click="Button_Click_2"/>
</Grid>
<Button x:Name="button1" Content="添加一个后台传输" HorizontalAlignment="Left" Margin="12,10,0,0" Grid.Row="1" VerticalAlignment="Top" Click="Button_Click_1"/>
</Grid>
[C#]
public partial class MainPage : PhoneApplicationPage
{
// 构造函数
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
initTransferRequest();
base.OnNavigatedTo(e);
}
private void initTransferRequest()
{
//获取第一个后台传输任务
var transferRequest = BackgroundTransferService.Requests.FirstOrDefault();
if (transferRequest == null)
{
textblock1.Text = "无后台传输任务";
button1.IsEnabled = true;
return;
}
//当传输状态改变时:
transferRequest.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
//当传输进度改变时:
transferRequest.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);
updatesStatus(transferRequest);
button1.IsEnabled = false;
}
void transfer_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
{
updatesStatus(e.Request);
}
void transfer_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
{
updatesStatus(e.Request);
}
void updatesStatus(BackgroundTransferRequest transferRequest)
{
textblock1.Text = "传输状态:" + transferRequest.TransferStatus.ToString()
+ " 已下载字节:" + transferRequest.BytesReceived
+ "总字节:" + transferRequest.TotalBytesToReceive;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string fileurlstring = "http://images.cnblogs.com/cnblogs_com/lipan/319399/o_Large.png";
Uri uri = new Uri(Uri.EscapeUriString(fileurlstring), UriKind.RelativeOrAbsolute);
BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(uri);
transferRequest.Method = "GET";
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isoStore.DirectoryExists("/shared/transfers"))
{
isoStore.CreateDirectory("/shared/transfers");
}
}
//文件下载后存放位置(为本地文件夹相对位置)
transferRequest.DownloadLocation = new Uri("shared/transfers/1.png", UriKind.RelativeOrAbsolute);
//外接电源、WiFi的可用性对传输的影响
transferRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
try
{
//添加到后台传输队列中
BackgroundTransferService.Add(transferRequest);
}
catch (Exception ex)
{
MessageBox.Show("无法添加后台传输请求。" + ex.Message);
}
initTransferRequest();
}
//清除传输队列已完成的任务
private void Button_Click_2(object sender, RoutedEventArgs e)
{
foreach (var transferRequest in BackgroundTransferService.Requests)
{
if (transferRequest.TransferStatus == TransferStatus.Completed)
{
try
{
BackgroundTransferService.Remove(transferRequest);
}
catch
{
}
}
}
initTransferRequest();
}
}
五、后台辅助线程
后台辅助线程虽然名字这么叫,但是它不能在后台运行,我们可以用它来执行一个任务,并且可以实时获取执行的进度,实现代码如下:
[XAML]
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="10" >
<Button x:Name="buttonStart" Content="开始" Click="buttonStart_Click"
Width="200" />
<Button x:Name="buttonCancel" Content="取消" Click="buttonCancel_Click"
Width="200" />
</StackPanel>
<StackPanel Margin="10,50,0,0" Orientation="Horizontal">
<TextBlock Text="进度: " />
<TextBlock x:Name="tbProgress" />
</StackPanel>
</StackPanel>
</Grid>
[C#]
public partial class MainPage : PhoneApplicationPage
{
private BackgroundWorker bw = new BackgroundWorker();
public MainPage()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
{
bw.CancelAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
this.tbProgress.Text = "Canceled!";
}
else if (!(e.Error == null))
{
this.tbProgress.Text = ("Error: " + e.Error.Message);
}
else
{
this.tbProgress.Text = "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
}
}
出处:[http://www.cnblogs.com/lipan/]
版权声明:本文的版权归作者与博客园共有。转载时须注明原文出处以及作者,并保留原文指向型链接,不得更改原文内容。否则作者将保留追究其法律责任。
发表评论
-
Javascript:猜猜弹出的是啥?为啥? - 幸福框架
2013-06-28 13:33 430原帖地址:http://www.cnblogs.com/hap ... -
C#中WindowsForm常见控件的运用 -- - 李晓峰
2013-06-28 13:27 1747原帖地址:http://www.cnblogs.com/liy ... -
海量数据处理利器之Hash——在线邮件地址过滤 - MyDetail
2013-06-27 12:00 654原帖地址:http://www.cnblo ... -
ASP.NET MVC 4 for Visual Studio 2010 下载地址 - 张鸿伟
2013-06-27 11:48 754原帖地址:http://www.cnblogs.com/wei ... -
【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化 - r01cn
2013-06-26 11:00 919原帖地址:http://www.cnblogs.com/r01 ... -
[珠玑之椟]估算的应用与Little定律 - 五岳
2013-06-26 10:54 639原帖地址:http://www.cnblogs.com/wuy ... -
30行,金额转人民币大写的代码 - 史蒂芬.王
2013-06-26 10:42 1028原帖地址:http://www.cnblogs.com/ste ... -
从银行的钱荒看一个公司的团队建设 产品线过多最终导致最赚钱的项目面临破产 - James Li
2013-06-26 10:36 632原帖地址:http://www.cnblogs.com/Jam ... -
Windows 8 动手实验系列教程 实验6:设置和首选项 - zigzagPath
2013-06-25 13:39 535原帖地址:http://www.cnblogs.com/zig ... -
闲聊可穿戴设备 - shawn.xie
2013-06-25 13:33 616原帖地址:http://www.cnblo ... -
如何使用开源库,吐在VS2013发布之前,顺便介绍下VS2013的新特性"Bootstrap" - 量子计算机
2013-06-25 13:27 869原帖地址:http://www.cnblogs.com/DSh ... -
一步一步将自己的代码转换为观察者模式 - 文酱
2013-06-23 11:36 611原帖地址:http://www.cnblo ... -
iOS内存错误EXC_BAD_ACCESS的解决方法(message sent to deallocated instance) - VicStudio
2013-06-23 11:30 543原帖地址:http://www.cnblogs.com/vic ... -
记录asp.net在IE10下事件丢失排错经过 - Adming
2013-06-23 11:24 712原帖地址:http://www.cnblogs.com/wea ... -
记 FineUI 官方论坛所遭受的一次真实网络攻击!做一个像 ice 有道德的黑客! - 三生石上
2013-06-23 11:18 793原帖地址:http://www.cnblogs.com/san ... -
3、使用Oracle Logminer同步Demo
2013-06-19 10:33 571原帖地址:http://www.cnblogs.com/shi ... -
算法实践——数独的基本解法
2013-06-19 10:27 1450原帖地址:http://www.cnblogs.com/gre ... -
简单实现TCP下的大文件高效传输
2013-06-19 10:21 692原帖地址:http://www.cnblogs.com/sma ... -
avalon - 初步接触
2013-06-18 10:06 785原帖地址:http://www.cnblogs.com/aar ... -
Nginx学习笔记(一) Nginx架构
2013-06-18 09:59 529原帖地址:http://www.cnblogs.com/cod ...
相关推荐
2. **了解用户界面**:通过第二章《The Windows Phone 7 Interface》,读者可以学习到Windows Phone 7的操作系统界面布局和常用操作方法,比如如何使用主屏幕、应用程序列表等。 #### 三、详细介绍与操作指导 - **...
3. **书籍和视频资源**:资料集中包含了一些书籍和视频教程,如《Windows Phone 7开发31日谈》和《Windows Phone 7开发探索笔记》,这些资源可以帮助开发者系统地学习WP7开发。 4. **XNA/Xbox Live游戏开发**:XNA...
《使用jQuery和CSS3创建Windows Phone 7手机切换效果》 在现代网页设计中,动态交互和视觉吸引力是提升用户体验的关键因素。本教程将详细解析如何利用jQuery和CSS3技术来实现一个仿Windows Phone 7手机界面的切换...
### C# 学习笔记关键知识点详解 #### C# 概述 - **定义与背景**:C# 是由微软公司开发的一种面向对象的高级程序设计语言,它运行于 .NET Framework 上。C# 由 Anders Hejlsberg 设计,首次亮相是在微软职业开发者...
### C#学习笔记知识点详解 #### 第一章:编程基础 **C#集合之ArrayList** - **概述**:`System.Collections.ArrayList` 类提供了一个动态数组的功能,能够存储任意类型的对象,且长度可变。 **.NET能做什么?** ...
相比之下,iPad的iOS系统在多任务处理和桌面体验方面相对较弱。 3. **Surface Pro 3的成功**:Surface Pro 3成功地结合了移动和桌面计算体验,提供了一种更加灵活的设备转换形式。这在一定程度上满足了用户对多功能...
在“JavaScript学习笔记之检测客户端类型”这个主题中,我们将深入探讨如何利用JavaScript来识别访问网页的客户端信息,包括浏览器渲染引擎、浏览器类型、操作系统平台、移动设备以及游戏系统。 1. **识别呈现引擎*...
用户可以创建多个桌面环境,每个桌面可以运行不同的应用程序,这样就可以轻松地在工作、学习和娱乐模式之间切换,提高了多任务处理的能力。 4. **Cortana语音助理**:Cortana,微软的人工智能助手,已经在Windows ...
它不局限于任何特定的操作系统,可以在iOS、Android、Windows Phone等多个平台上运行,因此在跨平台游戏开发中有着广泛的应用。OpenGL的优势在于其灵活性和广泛支持,但在某些特定功能和性能上可能不如DirectX。 ...
- `多线程编程指南`讲解了在iOS中如何处理并发和多任务,这对于优化性能和用户体验至关重要。 10. **市场和商业策略**: - `Iphone Money MakerCome Guadagnare con Apple iPhone e le Applicazioni di App Store...
12. **移动应用**: OneNote也有适用于iOS、Android和Windows Phone的移动应用,让你随时随地记录灵感。 13. **离线访问**: 如果在没有网络的情况下,OneNote会自动保存本地缓存,一旦连接恢复,将自动同步。 14. *...
【Windows编程】与【C++】是本次学习资源的核心关键词,这意味着这些文档主要涉及使用C++语言在Windows平台上进行软件开发。C++是一种强大的、通用的编程语言,它提供了面向对象编程的特性,并且在系统级编程和高...
不同的移动操作系统,如Android、iOS和Windows Phone,需要针对各自的平台进行开发。 开发App有多种方式,原生App能够充分利用设备特性,WebApp则跨平台性强,而Hybrid App试图兼顾两者。例如,微信小程序就是一种...
Windows拥有强大的办公软件支持,适合多任务处理。 4. Tizen、WebOS、Fire OS等:这些是针对特定设备或品牌定制的操作系统,如三星的智能电视和亚马逊的Kindle Fire平板电脑。 5. 智能家居操作系统:如Google Home...
10. **在不同的设备和平台上访问工作信息**:Office 2010的移动版本支持多种设备,如Windows Phone和早期的iOS设备,让用户随时随地访问和编辑文件。 **推荐作者简介**:虽然具体作者信息未在提供的内容中给出,但...
10. **兼容性**:确保插件能在主流的浏览器和移动设备上运行良好,包括Android、iOS和Windows Phone等平台。 通过下载并解压“jQuery移动端时间选择插件.zip”,开发者可以查看源码,学习如何实现上述特性,并将此...
- **Android与其他主流手机平台的比较**:比较Android与其他主流操作系统(如iOS、Windows Phone等)的异同之处。 - **Android原生(C/C++)程序开发及Android NDK介绍**:介绍如何使用C/C++语言进行Android原生应用...