WPF e Siverlight: Dispatcher e finestre modali

di Cristian Civera, in .NET 3.0,

Torno alla ribalta con un argomento che mi piace molto: il Dispatcher. E' un oggetto presente sia in WPF che in Silverlight ed è responsabile della coda di operazioni che si susseguono durate il ciclo di vita di un'operazione. Il comportamento è simile alla message pump di Win32: un ciclo continuo attende che una nuova DispatcherOperation venga accodata e la esegue appena possibile. L'unica differenza risiede nella possibilità di dare una priorità nell'operazione così da garantire per esempio che le operazioni di rendering abbiano la precedenza su quelle di input o su quelle di background.

In WPF attraverso la proprietà Hooks del Dispatcher si hanno a disposizione un po' di eventi per monitorare (occhio che si strozza parecchio il processamento delle richieste) l'accondamento delle operazioni. Per prima cosa si può notare quante operazioni vengono eseguite senza che ce ne accorgiamo. Il thread infatti è uno solo e la fluidità che si può percepire nell'interazione con i controlli o nelle animazioni è solo data dal fatto che la macchina processa le operazioni velocemente, ma ecco perché non appena si esegue qualcosa di più dispendioso per la CPU o si resta in attesa di una risposta, si causa il blocco dell'intera applicazione.

Nel thread del Dispatcher infatti ci finiscono tutti gli input da tastiera, mouse e altri device (il touch in futuro), arrivano i messaggi dalle altre finestre Win32, vengono gestiti gli handler degli eventi dei controlli e quindi eseguito il proprio codice, viene effettuato il rendering di tutti gli elementi presenti nell'applicazione e vengono inoltre gestite tutte le animazioni. Un semplice oggetto con Storyboard associata che varia per esempio nel tempo la larghezza dell'elemento, fa sì che nel dispatcher vengano accodate tantissime operazioni, fino anche 50/60 al secondo, pari a quanti frame al secondo si intende renderizzare. E' interessante poi notare attraverso l'evento OperationAborted come, nel caso la CPU non è in grado di soddisfare tale rate o per rallentamenti dovuti ad operazioni intermedie fra un frame e l'altro, il motore abortistica alcuni di questi frame, sacrificando la fluidità, ma mantenendo l'obiettivo: raggiungere un valore in un intervallo ben preciso. Questa è una delle principali differenze che Silverlight ha con Flash dove quest'ultimo lavora ad un frame rate fisso preindicato, ignorando il carico di lavoro che la macchina ha.

In WPF inoltre si ha a disposizione il signor DispatcherFrame che permette di aprire una finestra sul medesimo thread, bloccando però il creatore della finestra. Questa tecnica viene utilizzata per le finestre modali dove chiamando ShowDialog il chiamante del metodo attende che la finestra venga chiusa, mentre tutte le operazioni accodate nel Dispatcher vengano comunque processate al suo interno, mantenendo attive le animazioni della finestra chiamante e della finestra modale, e reagendo agli input dell'utente. Il fatto che sulla finestra chiamante non si possa interagire è solo un impedimento di Windows, ma tecnicamente è possibile accodare operazioni che intervengano su di essa.

Il DispatcherFrame può essere usato anche per un uso alternativo. Per capirci su un click di pulsante si può fare:

DispatcherFrame frame = new DispatcherFrame(true); 

Debug.WriteLine("Creazione DispatcherFrame"); 

// Timer che scatta dopo 3 secondi 
System.Timers.Timer timer = new System.Timers.Timer(3000); 
timer.AutoReset = false; 
timer.Elapsed += delegate 
{ 
    Debug.WriteLine("Frame in termine"); 
    frame.Continue = false; 
}; 
timer.Start(); 

// Avvio il frame e attendo che finisca 
Dispatcher.PushFrame(frame); 

Debug.WriteLine("Frame uscito");

Se eseguito, nonostate il timer scatti dopo tre secondi dando tutto il tempo di processare l'istruzione "Frame uscito", l'output è:

Creazione DispatcherFrame
Frame in termine
Frame uscito

Purtroppo questa funzione non c'è in Silverlight 2.0, perciò l'unico rimedio è mostrare la "finta" finestra di dialogo e intercettare un evento che notifichi la sua chiusura. Per impedire invece di interagire con la finestra principale, occorre posizionare un elemento grafico trasparente che copra l'intera superficie da disattivare. In Silverlight 3.0 sarà invece presente una ChildWindow che semplificherà la vita :-)

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.

Nella stessa categoria
I più letti del mese