Cosa è RX Framework
RX è una libreria per comporre i dati provenienti da operazioni asincrone e dagli eventi in un'unica collezione osservabile. Questa è la definizione che ne viene data nella home page di DevLabs, il sito che ospita alcuni progetti più interessanti dei laboratori di Microsoft.
La missione della libreria RX è quella di facilitare la programmazione asincrona e ad eventi. Queste due tecniche sono diventate indispensabili per gestire correttamente l'accesso ai dati, sempre più in "the cloud", e le UI che devono rimanere reattive e mai bloccate.
Sappiamo quanto sia frustante avere a che fare con UI che rimangono congelate durante operazioni lunghe, come consumare un web service, e sappiamo anche quanto sia complesso gestire e mantenere l'event handler per gli eventi dell'UI e i callback di un servizio, oltre a far interagire il tutto al fine di creare un'esperienza omogenea all'utente.
Nel corso di questo articolo vedremo come utilizzare la libreria RX per realizzare una semplice applicazione, allo scopo di eseguire una ricerca sul wall di Twitter e come sia semplice comporre eventi e chiamate asincrone in un unico flusso di informazioni.
Iniziamo: i giusti riferimenti
Iniziamo creando un nuovo progetto Windows Phone, chiamiamolo RXDemo e aggiungiamo i riferimenti ai seguenti assembly:
- System.Observable.dll: contiene le interfacce IObservable<T> e IObserver<T>, in altre piattaforme, come il .NET 4, il riferimento non è necessario;
- Microsoft.Phone.Reactive.dll: contiene gli e extension methods e i tipi che permettono di creare e comporre le observable collection e gli observer, chiariremo in seguito il loro ruolo e funzionamento.
Gli assembly utilizzati nell'articolo sono stati rilasciati con Windows Phone 7, in alternativa è possibile utilizzare l'ultima versione disponibile pubblicata nelblog dell'RX team. Ci sono dei pro e dei contro nell'utilizzare l'ultima versione rispetto a quella rilasciata con la piattaforma Windows Phone 7: tra i pro abbiamo la disponibilità di nuove funzioni, che non saranno presenti nella piattaforma fino ad una major release. Tra i contro c'è il supporto che viene erogato solo tramite forum e un incremento delle dimensioni del file xap, in quanto il nuovo assembly deve essere pubblicato sul device.
Diamo adesso uno sguardo alle due interfacce presenti nell'assembly System.Observable.dll
public interface IObservable<out T> { IDisposable Subscribe(IObserver<T> observer); } public interface IObserver<in T> { void OnCompleted(); void OnError(Exception error); void OnNext(T value); }
Le due interfacce sono complementari, l'interfaccia IObservable<T> rappresenta la sorgente dati che può essere "osservata", in altre parole, chi implementa questa interfaccia può "spedire" dati a chiunque è interessato, ovvero un "osservatore" rappresentato dall'interfaccia IObserver<T>.
Per ricevere le notifiche dalla observable collection, la stessa implementa il metodo Subscribe e restituisce un riferimento ad un oggetto che implementa l'interfaccia IDisposable. Richiamare il metodo Dispose su quest'oggetto fa in modo che l'observer non riceva più notifiche dalla observable collection. E' possibile trovare delle analogie (non casuali) tra i metodi Subscribe e Dispose e gli operatori += e -= usati in .NET per registare e cancellare un'event handler.
Possiamo trovare anche una similitudine con le interfacce IEnumerable<T> e IEnumerator<T> ma con una sostanziale differenza: mentre l'enumeratore esegue il polling sulla collezione, tipicamente attraverso un ciclo foreach, l'observer riceve in push i dati dalla observable collection.
Difficilmente troveremo direttamente implementate queste due classi per questo motivo: il tipo Observable (namespace Microsoft.Phone.Reactive) dispone di una serie di factory method per creare una observable collection da diverse tipi di fonti dati.
Prima di creare la nostra prima observable collection è necessario aggiungere una serie di controlli alla nostra applicazione. Apriamo quindi il designer del Visual Studio o Expression Blend, e aggiungiamo una TextBox e ListBox, che utilizzeremo rispettivamente per inserire i termini della ricerca e per visualizzarne i risultati. Assegniamo tramite l'attributo x:Name il nome di SerchText alla TextBox e SearchResultListBox alla ListBox, potremo così accedere ai due controlli da code behind.
Per questa applicazione, vista la semplicità, piuttosto che realizzare un'apposito View Model, utilizzeremo direttamente la classe di code behind.
Gestire gli eventi
Nel costruttore della pagina, subito dopo la chiamata al metodo InitializeComponent, registriamo un event handler per l'evento Loaded, e andiamo ad aggiungere il codice seguente.
var textChanged = from event in Observable.FromEvent<TextChangedEventArgs>(SearchText, "TextChanged") select ((TextBox)evt.Sender).Text;
Come abbiamo detto, è difficile trovare un implementazione diretta dell'inerfaccia IObservable<T>, per questo motivo utilizziamo il metodo FromEvent<T> esposto dalla classe statica Observable dove T è il tipo di dato generato dall'evento; per creare una observable collection dall'evento TextChanged, in questo caso, passiamo come argomenti l'oggetto e l'evento da "monitorare".
In questo modo, insieme all'uso degli Standard Query Operators di Linq, come il select, si crea di fatto un flusso di dati contenente il testo digitato dall'utente.
A questo punto il nostro flusso dati è pronto e non ci rimane che gestirlo, per adesso ci limiteremo a visualizzare in una MessageBox il testo digitato dall'utente, aggiungiamo quindi il codice seguente:
textChanged.Subscribe((text) => MessageBox.Show(string.Format("Hai digitato:{0}",text)));
Utilizzando il metodo Subscribe ogni volta che l'utente modifica il testo nella TexBox sarà visualizzata una MessageBox con il testo inserito. Non ci resta che provare la nostra applicazione premendo il tasto F5.
L'immagine precedente mostra la MessageBox con il testo digitato dall'utente, possiamo anche notare che riceviamo la notifica per ognuna delle lettere digitate. Dovendo usare l'input dell'utente per interrogare un servizio, farlo per ogni lettera non è certo una buona pratica sia dal punto di vista dell'impatto che questo avrebbe sulle performance, sia in termini del risultato delle ricerca. L'obbiettivo è chiamare il servizio solo quando l'utente è riuscito a comporre una parola e che la parola risponda a determinati requisiti.
Tutto questo è facilmente realizzabile utilizzando uno degli Extension Methods disponibili nell'assembly Microsoft.Phone.Reactive.dll.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Sfruttare al massimo i topic space di Event Grid MQTT
Eseguire una query su SQL Azure tramite un workflow di GitHub
Utilizzare gRPC su App Service di Azure
Eseguire una ricerca avanzata per recuperare le issue di GitHub
Sostituire la GitHub Action di login su private registry
Estrarre dati randomici da una lista di oggetti in C#
Hosting di componenti WebAssembly in un'applicazione Blazor static
Applicare un filtro per recuperare alcune issue di GitHub
Supportare lo HierarchyID di Sql Server in Entity Framework 8
Esportare ed analizzare le issue di GitHub con la CLI e GraphQL
Aprire una finestra di dialogo per selezionare una directory in WPF e .NET 8
Proteggere le risorse Azure con private link e private endpoints