Gestire i problemi con i threads in Windows Presentation Foundation

di Cristian Civera, in Windows Presentation Foundation, XAML,

Windows Presentation Foundation è un nuovo motore, completamente riscritto, che si discosta dal mondo Win32. Rispetto agli altri framework come WinForms, MFC, ATL o Delphi non si basa sulle API di Windows e per questo è stato pensato cercando di risolvere alcune problematiche molto comuni. Una di queste è la gestione dei messaggi che, in Win32, vengono accumulati e gestiti singolarmente da un unico thread, solitamente conosciuto come UI Thread. Spesso questo si trasforma in un collo di bottiglia, poiché non tutti i messaggi hanno la medesima priorità e non tutti vengono processati nella stessa velocità. Questo si traduce in interfacce bloccate quando si eseguono operazioni sul thread principale oppure finestre che non si disegnano perché il messaggio di paint non è ancora stato processato.

In WPF è mantenuto il singolo thread, ma ogni operazione da compiere ha una priorità così che il motore possa dare precedenza a quelle più importanti, come quelle di rendering, a scapito di quelle meno essenziali, come le operazioni in background.

Il gestore dei messaggi è rappresentato dalla classe Dispatcher (namespace System.Windows.Threading) che dispone dei metodi Invoke e BeginInvoke per accodare nuove operazioni da compiere. Il primo fa sì che il thread chiamante (diverso da quello di UI) attenda l'esecuzione del delegate passato, mentre il secondo fa proseguire chi ha chiamato il metodo. Questi vengono utili quando si desidera chiamare in asincrono un metodo che impiega lungo tempo e non si vuole fermare l'interfaccia utente. La classe DispatcherObject, dalla quale ereditano tutti gli elementi e controlli di WPF, dispone di una proprietà Dispatcher che restituisce appunto un riferimento all'omonima classe. Ecco quindi un esempio per invocare in asincrono un metodo per poi chiamare sul thread principale un metodo di notifica:

private delegate void MethodInvoker();

void Button_Click(object s, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(DoOperation);
}

void DoOperation(object state)
{
    // Faccio qualcosa che impiega molto tempo
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
    // Invoco sul thread principale
    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new MethodInvoker(EndOperation));
}

void EndOperation()
{
    this.VerifyAccess();
    myLabel.Text = "Operazione conclusa";
}

La classe DispatcherObject dispone inoltre dei metodi CheckAccess e VerifyAccess rispettivamente per restituire se il thread dello stack in esecuzione sia quello principale, mentre il secondo genera un'eccezione in caso non corrisponda.
Tramite l'oggetto Dispatcher è inoltre possibile controllare eventuali eccezioni non gestite scatenante nell'intera applicazione. L'evento utile a tale scopo è UnhandledException che generalmente si intercetta a livello di entry point dell'applicazione.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

Nessuna risorsa collegata

I più letti di oggi