Con l'avvento di Windows Phone 7.1, Microsoft ha introdotto alcune nuove caratteristiche per colmare la mancanza del multitasking della versione precedente. Per limitare il consumo della batteria e salvaguardare l'utente, solo un'applicazione può essere attiva in foreground e sebbene questo limite sia ancora presente, è possibile sfruttare i background agent per soddisfare la maggior parte delle esigenze che una applicazione possa avere.
Un background agent dal punto di vista dell'utente è un'attività che una applicazione può programmare di eseguire anche se l'applicazione non è attiva. Nelle impostazioni esiste un riquadro apposito di nome "attività in background", che permette di monitorarle e disattivarle. Dal punto di vista dello sviluppatore, i background agent sono classi che ereditano dalla classe ScheduledTaskAgent e implementano il metodo OnInvoke, per inserire la logica da eseguire. Vengono eseguiti in un processo diverso da quello dell'applicazione che lo detiene e potrebbero essere eseguiti contemporaneamente ad essa.
In Visual Studio 2010 è possibile creare un nuovo progetto di tipo "Windows Phone Scheduled Task Agent" che già crea una classe e il codice base. Una volta implementato è necessario referenziare tale progetto nell'applicazione Windows Phone che necessita del task. Questo fa sì che automaticamente il file WMAppManifest.xml venga modificato inserendo un tag BackgroundServiceAgent, fondamentale per l'individuazione della classe da istanziare ed eseguire.
Nello script si propone la creazione di un task che aggiorni la tile ciclando su un set di webcam da mostrare. Si procede quindi con la creazione del progetto e l'implementazione della classe, come nello snippet seguente.
public class ScheduledAgent : ScheduledTaskAgent
{
protected override void OnInvoke(ScheduledTask task)
{
// Recupero la tile associata all'applicazione
ShellTile tile = ShellTile.ActiveTiles.First();
// Recupero l'ultimo indice dell'array utilizzato come immagine webcam
int index;
if (IsolatedStorageSettings.ApplicationSettings.TryGetValue("index", out index))
{
index++;
if (index >= images.Length)
index = 0;
}
// Aggiorno la tile
StandardTileData data = new StandardTileData
{
Title = images[index][0],
BackgroundImage = new Uri(images[index][1]),
BackBackgroundImage = new Uri(images[index][1]),
BackContent = "Aggiornato alle " + DateTime.Now.ToShortTimeString(),
};
tile.Update(data);
// Salvo l'indice della webcam utilizzata
IsolatedStorageSettings.ApplicationSettings["index"] = index;
IsolatedStorageSettings.ApplicationSettings.Save();
NotifyComplete();
}
private string[][] images = new[]
{
new[] {"Via Veneto", "http://images.webcams.travel/webcam/1267635323.jpg"},
new[] {"Raccordo anulare", "http://get.edidomus.it/vp/cam27/image.jpg"}
};
}Nel codice precedente si ottiene un riferimento alla tile dell'applicazione, che è sempre presente, anche se non pinnata. Si recupera dai settings l'indice dell'ultima webcam mostrata e si aggiorna la tile con la webcam successiva. Infine si salva l'indice e si notifica il sistema che il task è concluso mediante la chiamata NotifyComplete. E' possibile chiamare Abort se il task non è andato a buon fine, evitando che questo venga ripetuto, se previsto dalla programmazione.
Una volta sviluppato il task, nel punto che si ritiene opportuno (in questo caso non appena avviata l'app) è necessario programmare l'esecuzione del task. Per farlo occorre chiamare il metodo statico Add della classe ScheduledActionService passando la programmazione del task. Questa può essere di due tipi:
- PeriodicTask: task eseguiti ogni 30 minuti e per un massimo di 15 secondi, ideali per piccole attività;
- ResourceIntensiveTask: task eseguiti solo con wi-fi, con il device in ricarica e per un massimo di 10 minuti.
Un'applicazione può programmare entrambe i tipi di task (uno solo per tipo), ma l'implementazione è sempre la stessa, poiché essa può discriminare in base al tipo di task passato al metodo OnInvoke. Entrambe le tipologie di task scadono dopo 14 giorni dalla loro creazione, se non diversamente specificato e comunque non oltre quel termine. Questo limite è impostato per evitare che l'utente si dimentichi di attività in background dopo un lungo periodo di inattività. Per evitare che il task scada, è compito del programmatore rischedularla ogni qual volta l'utente avvia l'applicazione. Nel codice seguente quindi si verifica l'esistenza del task così da rimuoverlo e crearne uno nuovo.
const string taskName = "update";
// Cerco e rimuovo il task, se presente
if (ScheduledActionService.Find(taskName) != null)
ScheduledActionService.Remove(taskName);
// Creo il task
PeriodicTask task = new PeriodicTask(taskName);
task.Description = "Aggiorna l'immagine della webcam";
try
{
// Schedulo il task
ScheduledActionService.Add(task);
}
catch (InvalidOperationException exception)
{
// Controllo che il backgroun task non sia disattivato
if (exception.Message.Contains("BNS Error: The action is disabled"))
{
MessageBox.Show("Impossibile aggiornare la webcam perché le attività in background sono disabilitate per questa applicazione");
}
}La gestione dell'eccezione è necessaria in quanto l'utente potrebbe dal pannello disattivare il task dell'applicazione, perciò si notifica l'utente di riattivare il task relativo. Il nome del task è ad uso interno, non va in conflitto con altre applicazioni e non riguarda il nome della classe del task.
A questo punto è possibile avviare l'applicazione e osservarne la tile.

Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
.NET Aspire per applicazioni distribuite
La gestione della riconnessione al server di Blazor in .NET 9
Ricevere notifiche sui test con Azure Load Testing
Anonimizzare i dati sensibili nei log di Azure Front Door
Evitare memory leaks nelle closure JavaScript
Eseguire query in contemporanea con EF
Mischiare codice server side e client side in una query LINQ con Entity Framework
Utilizzare @property per animare nativamente un oggetto HTML tramite CSS
Ospitare n8n su Azure App Service
Usare la libreria PredicateBuilder per eseguire query tramite Entity Framework che usano or su più campi
Utilizzare DeepSeek R1 con Azure AI
Integrare Agenti A2A in Azure API Management


