Mango brings a number of new features to support background processing; many of which I’ll be covering in coming days and weeks. The most general of all of these is the Background Agent.
Background Agents come in two flavors:
- PeriodicTask
- ResourceIntensiveTask
The PeriodicTask runs approximately every 30 minutes, for about 25 seconds. This is perfect for updating tiles, sending toast notifications or otherwise keeping the user updated as to the status of, e.g., an application that retrieves data from a web service.
The ResourceIntensiveTask, on the other hand, run when certain conditions are met (the phone is connected to wifi or a computer rather than the cellular network, the phone is plugged into A/C rather than running on battery, the battery must in any case be at least 90% charged, etc.) The advantage of the ResourceIntensiveTask is that it will run for approximately 10 minutes at a time, allowing for more, err, Resource Intensive tasks, such as synchronizing a local and a distributed database.
The actual setup and use of both types is very similar, as is made obvious by the Sample program on MSDN. This article strips that sample down to just the Periodic Task to make clear how easy it is to create and use a Background Agent.
The key to working with Background Agents is that you will create two projects in one solution:
- The Main (foreground) project – which will contain the UI
- A Task Agent project – with a class that derives from ScheduledTaskAgent
Fortunately, there is a Visual Studio template of type Windows Phone Scheduled Task Agent that creates just what we need for the second project.
To see this at work, begin by creating a Windows Phone project (using the Windows Phone Application template). Name it BackgroundAgents. Add a second project using the Windows Phone Scheduled Task Agent template. You can use the default name of ScheduledTaskAgent1.
Critically important is that you create a reference to the second project in the first project (click on the foreground project, then click Add Reference…. and use the Project tab to find and select the project).
The Scheduled Task Agent project has one class, ScheduledAgent, which has one important method, OnInvoke. This method is called whenever the Task is launched. It is also critically important that you call NotifyComplete() when this method completes its work successfully or Abort() if it cannot complete its work.
Here’s the code we’ll add to OnInvoke, which will create a toast message and display it periodically (approximately every 30 minutes unless you are debugging, in which case, approximately every 30 seconds).
protected override void OnInvoke( ScheduledTask task ) { string toastMessage = "Periodic task running."; ShellToast toast = new ShellToast(); toast.Title = "Background Agent Sample"; toast.Content = toastMessage; toast.Show(); #if DEBUG_AGENT ScheduledActionService.LaunchForTest( task.Name, TimeSpan.FromSeconds(30)); #endif NotifyComplete(); }
All that’s left to do is to fire off the task, which we do in the foreground application. The key bit of Xaml is the checkbox that is used to start and stop the task,
<CheckBox Name="PeriodicCheckBox" IsChecked="{Binding IsEnabled}" Checked="PeriodicCheckBox_Checked" Unchecked="PeriodicCheckBox_Unchecked" />
The checked and unchecked event handlers are in the code behind,
private void PeriodicCheckBox_Checked( object sender, RoutedEventArgs e ) { StartPeriodicAgent(); } private void PeriodicCheckBox_Unchecked( object sender, RoutedEventArgs e ) { RemoveAgent( periodicTaskName ); }
RemoveAgent is simpler, so let’s look at that first. YOu need only call Remove on the SecheduledActionService, passing in the name of the agent and catching any resulting exception (there is no action to take in the case of an exception except to not crash).
private void RemoveAgent( string name ) { try { ScheduledActionService.Remove( name ); } catch (Exception) { } }
The more interesting code is in StartPeriodicAgent; our method for firing up a PeriodicTask. This is done in two steps:
- Remove the task if it already exists
- Add the task (and handle the exception if background agents for this application are disabled)
private void StartPeriodicAgent() { AgentIsEnabled = true; // If this task already exists, remove it periodicTask = ScheduledActionService.Find( periodicTaskName ) as PeriodicTask; if (periodicTask != null) { RemoveAgent( periodicTaskName ); } periodicTask = new PeriodicTask( periodicTaskName ); periodicTask.Description = "This demonstrates a periodic task."; try { ScheduledActionService.Add( periodicTask ); PeriodicStackPanel.DataContext = periodicTask; #if(DEBUG_AGENT) ScheduledActionService.LaunchForTest( periodicTaskName, TimeSpan.FromSeconds( 20 ) ); #endif } catch (InvalidOperationException exception) { if (exception.Message.Contains( "BNS Error: The action is disabled" )) { MessageBox.Show( "Background agents for this application have been disabled by the user." ); AgentIsEnabled = false; PeriodicCheckBox.IsChecked = false; } } }
Finally, when we navigate to the page we test to see if this task already exists; if so we assign it as the datacontext for the display StackPanel,
protected override void OnNavigatedTo( System.Windows.Navigation.NavigationEventArgs e ) { periodicTask = ScheduledActionService.Find( periodicTaskName ) as PeriodicTask; if (periodicTask != null) { PeriodicStackPanel.DataContext = periodicTask; } }
For completeness, here is the entire Xaml from the ContentPanel:
<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="Periodic Agent" Style="{StaticResource PhoneTextTitle2Style}" /> <StackPanel Orientation="Horizontal"> <TextBlock Text="name: " Style="{StaticResource PhoneTextAccentStyle}" /> <TextBlock Text="{Binding Name}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="is enabled" VerticalAlignment="Center" Style="{StaticResource PhoneTextAccentStyle}" /> <CheckBox Name="PeriodicCheckBox" IsChecked="{Binding IsEnabled}" Checked="PeriodicCheckBox_Checked" Unchecked="PeriodicCheckBox_Unchecked" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="is scheduled: " Style="{StaticResource PhoneTextAccentStyle}" /> <TextBlock Text="{Binding IsScheduled}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="last scheduled time: " Style="{StaticResource PhoneTextAccentStyle}" /> <TextBlock Text="{Binding LastScheduledTime}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="expiration time: " Style="{StaticResource PhoneTextAccentStyle}" /> <TextBlock Text="{Binding ExpirationTime}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="last exit reason: " Style="{StaticResource PhoneTextAccentStyle}" /> <TextBlock Text="{Binding LastExitReason}" /> </StackPanel> </StackPanel> </StackPanel> </Grid>
See also this video.
hello there and thank you to your info ? I’ve definitely picked up something new from proper here. I did on the other hand expertise some technical points the usage of this web site, since I skilled to reload the web site a lot of times prior to I may just get it to load correctly. I were pondering if your web host is OK? Now not that I am complaining, however sluggish loading instances times will often impact your placement in google and could damage your high quality ranking if advertising and marketing with Adwords. Anyway I’m including this RSS to my e-mail and could look out for much more of your respective interesting content. Make sure you replace this once more very soon..
I see that only Periodic Task appear in the Background Tasks setting in the phone. Why is that
Hi. I understand the use of background agents but I had a scenario in mind and wanted help in understanding how to realize this in windows phone. Suppose my background task checks for location of the phone and does some job when the location matches. How should I do this. Periodic tasks do not run on 256MB devices. They do not get invoked if battery is low. These tasks typically run every 30min. But the location can change every sec or in couple of sec. Please help me with this, I am new to windows phone development.
Yours is the classic case of what one would want to do, but can’t with the current Windows Phone technology — for precisely the reasons you state. As far as I know, it can’t be done unless the user keeps the application open, which of course is not workable.
-jesse
Moin, in Windows Phone 8 you can do this now. There is a thing called continuous tracking. Have a look at http://www.adambenoit.com/development/continuous-location-tracking-windows-phone-8/