1. Periodic Agent
using Microsoft.Phone.Scheduler;
public class ScheduledAgent : ScheduledTaskAgent
{
static ScheduledAgent()
{
// Subscribe to the managed exception handler
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
Application.Current.UnhandledException += UnhandledException;
});
}
static void UnhandledException(object sender,
ApplicationUnhandledExceptionEventArgs e)
{
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
protected override void OnInvoke(ScheduledTask task)
{
//TODO: Add code to perform your task in background
NotifyComplete();
}
}
ScheduledAgent
class created overrides a single method (OnInvoke
) that the operating system calls when the background agent is executed. You should do your work in this method and have the call to NotifyComplete
be the last line of code in this method. The NotifyComplete
method tells the operating system that your operation is complete. For example, to save a file with the current time in isolated storage (so your UI app can use it), you could do this:protected async override void OnInvoke(ScheduledTask task)
{
var folder = ApplicationData.Current.LocalFolder;
using (var stream =
await folder.OpenStreamForWriteAsync(“time.txt”,
CreationCollisionOption.ReplaceExisting))
{
var writer = new StreamWriter(file);
writer.WriteLine(DateTime.Now);
}
NotifyComplete();
}
NotifyComplete
method when you have completed your operation. You also might want to know whether the operation fails. You can accomplish this by calling the Abort
method:try
{
var folder = ApplicationData.Current.LocalFolder;
using (var stream =
await folder.OpenStreamForWriteAsync(“time.txt”,
CreationCollisionOption.ReplaceExisting))
{
var writer = new StreamWriter(stream);
writer.WriteLine(DateTime.Now);
}
NotifyComplete();
}
catch
{
Abort();}
NotifyComplete
or Abort
in your agent, to let the runtime (and potentially your application) know whether the task was successfully completed.WMAppManifest.xml
file:
<App …>
…
<Tasks>
<DefaultTask Name=”_default”
NavigationPage=”MainPage.xaml” />
<ExtendedTask Name=”BackgroundTask”>
<BackgroundServiceAgent Specifier=”ScheduledTaskAgent”
Name=”BackgroundAgent”
Source=”BackgroundAgent”
Type=”BackgroundAgent.ScheduledAgent”
/>
</ExtendedTask>
</Tasks>
…
</App>
</Deployment>
Tasks
element, the project item added a section called ExtendedTask
, which is responsible for indicating the project and code for any background tasks. The ExtendedTask
element is where all agents are registered, including periodic, resource-intensive, and audio agents. Although the ExtendedTask
is named, the name is not significant. Inside the ExtendedTask
element is a set of elements that reference the different background agent or agents in your application. Each attribute in the BackgroundServiceAgent
element has a specific meaning:- Name: This is the name of the element, not referenced in code.
- Specifier: This is the type of agent. The types of specifiers are as follows:
– ScheduledTaskAgent: This is a periodic or resource-intensive task.
– AudioPlayerAgent: This task plays specific songs from a list of audio files.
– AudioStreamingAgent: This task streams audio directly to the phone.
- Source: This is the assembly name that contains the background agent.
- Type: This is the type of the class that represents the background agent.
WMAppManifest.xml
file is what links your application to the assembly that contains your background task. This means your background agent must be in a separate assembly (as the separate project would indicate). You still have to do a little more work to make your agent actually run in the background.
PeriodicTask
class:// A unique name for your task. It is used to
// locate it in from the service.
var taskName = “MyTask”;
// Create the Task
PeriodicTask task = new PeriodicTask(taskName);
// Description is required
task.Description = “This saves some data to Isolated Storage”;
// Add it to the service to execute
ScheduledActionService.Add(task);
WMAppManifest.xml
file. After your task is created, you must set the Description
property as well (at a minimum). After your PeriodicTask
object is constructed, you can add it to the phone by using the ScheduledActionService
’s Add
method as shown. This will cause your background task to be periodically executed (every 30 minutes).Description
property of the PeriodicTask
class to something significant. The description is a string that is visible to the end user and that is shown in the background task management UI.
// A unique name for your task. It is used to
// locate it in from the service.
var taskName = “MyTask”;
// If the task existsvar oldTask = ScheduledActionService.Find(taskName);if (oldTask != null){ ScheduledActionService.Remove(taskName);}
// Create the Task
PeriodicTask task = new PeriodicTask(taskName);
// Description is required
task.Description = “This saves some data to Isolated Storage”;
// Add it to the service to execute
ScheduledActionService.Add(task);
Now that you have your agent registered, you will need to be able to debug it. The problem on the face of it is that you might not want to wait the 30 minutes for your agent to execute. The ScheduledActionService
has a way to run the agent immediately so that you can debug it more easily:
var taskName = “MyTask”;
ScheduledActionService.LaunchForTest(taskName, TimeSpan.FromMilliseconds(250));
LaunchForTest
method takes the name of the task (which you specified earlier when you created the PeriodicTask
) and a delay before the task is launched. Lastly, because the background task (in this example) was able to write to isolated storage, you can access that data in your main application anytime you want. The background task and your application simply need to communicate by storing information in these shared locations (local folder, the Internet, or reading from the installation folder).ShellToast
class to open a toast (or update Live Tiles):protected override void OnInvoke(ScheduledTask task)
{
// If the Main App is Running, Toast will not show
ShellToast popupMessage = new ShellToast() { Title = “My First Agent”, Content = “Background Task Launched”, NavigationUri = new Uri(“/Views/DeepLink.xaml”, UriKind.Relative) }; popupMessage.Show();
NotifyComplete();
}
ShellToast
class, you can alert the user that the background task detected something and give her a chance to launch the application. If the main application is currently running, the ShellToast
class will not show the pop-up and will be reserved to show when your application is not currently being executed.