2012-01-18 13 views
6

Ho esaminato gli esempi di ReactiveUi dai blog e mi chiedo se ReactiveUI abbia una sorta di funzione di gestione delle sottoscrizioni al di sotto o gli esempi ignorino il fatto che potrebbero perdere le sottoscrizioni?ReactiveUI perde le sottoscrizioni?

Ogni volta che chiamo un metodo in ReactiveUi che risulta in un IDisposable, è necessario mantenere tale riferimento e tracciarlo da solo? Questo significa anche che i miei ViewModels devono essere usa e getta, questo sembra difficile dal momento che non sappiamo veramente quando le "viste" connesse vanno via (cioè se il mio ViewModel riflette gli elementi in una griglia di dati) in WPF quindi sembra che non ci sia luogo per chiamare smaltire.

risposta

10

È necessario solo mantenere i riferimenti allo IDisposable restituiti dagli abbonamenti se è necessario annullare l'iscrizione all'inizio di da un osservabile. Gli osservabili chiamano naturalmente Dispose quando terminano con i messaggi OnCompleted o OnError.

Tuttavia, è necessario mantenere i riferimenti quando si dispone di un abbonamento infinito osservabile (ad esempio FromEventPattern), ma questo è esattamente lo stesso che è necessario rimuovere i gestori di eventi prima di chiudere una maschera/vista.

+0

In genere non è necessario rimuovere i gestori di eventi al termine del modulo se la durata del publisher è uguale o inferiore alla durata del sottoscrittore.Ad esempio, lo stesso principio si applica a ReactiveCommand? – KolA

+1

@KolA - Suggerisco di disporre esplicitamente di tutte le sottoscrizioni Rx se si sa che alcuni potrebbero essere ancora in esecuzione solo per essere sicuri. È abbastanza facile avere un 'Form ComposableDisposable' a livello di modulo per monitorare tutte le sottoscrizioni. Significa solo un singolo '.Dispose()' quando esci. Come gli eventi regolari, potresti andartene senza farlo, ma non è sempre così. – Enigmativity

13

È inoltre necessario ricordare che gli IDisposables restituiti da Rx e ReactiveUI non sono associati alla memoria non gestita: si tratta solo di semplici oggetti .NET, ancora rifiutati dal garbage collector.

La maggior parte delle sottoscrizioni effettuate nei costruttori di ReactiveObjects saranno legate alla durata dell'oggetto host, quindi quando si passa fuori dal campo di applicazione ed è soggetta a GC, così tutti gli abbonamenti, il CLR rileverà il riferimento circolare e solo nuke tutto.

Come menziona l'enigmatività, l'unico problema è quando si utilizza FromEventPattern per legare la durata di una sottoscrizione (e forse un ViewModel) alla durata di un oggetto WPF. Tuttavia, direi che se utilizzi FromEventPattern spesso in ReactiveUI, sei sicuramente Doing It Wrong ™.

RxUI è tutto ViewModels e ViewModels sono tutti circa comandi e proprietà (e cablaggio fino come le proprietà sono correlate tra loro), in modo da poter testare il comportamento di esperienza degli utenti separatamente dalla sua grafica .

+0

Ma l'utilizzo delle proprietà e degli "eventi" osservati modificati non è possibile solo utilizzando da EventPattern sugli eventi PropertyChanged e PropertyChanging? E non è l'uso dei comandi che si agganciano all'evento Eseguito? Immagino che questo sia ciò che mi preoccupa. – Damian

+0

No, internamente ReactiveObject utilizza un oggetto, non si utilizza FromEventPattern quando si utilizza ObservableForProperty o WhenAny –

+0

Ok. Grazie per il chiarimento. Segnalo come risposta la risposta di Enigmativity da quando aveva ragione, ma il tuo chiarimento era cruciale per il mio livello di conversione. – Damian

2

Giusto per essere sicuro userò questo modello d'ora in poi. Probabilmente userò la modifica di tramite i metodi di estensione, ma il principio è valido. Per essere sicuri di non perdano abbonamenti si vuole far cadere loro

class Mesh2D{ 

    public Mesh2D() 
    { 
     DisposeOnUnload(CreateBindings()); 
    } 

    // Register all disposables for disposal on 
    // UIElement.Unload event. This should be 
    // moved to an extension method. 
    void DisposeOnUnload(IEnumerable<IDisposable> disposables) 
    { 
     var d = new CompositeDisposable(disposables); 
     var d2 = this.UnloadedObserver() 
      .Subscribe(e => d.Dispose()); 
     var d3 = this.Dispatcher.ShutdownStartedObserver() 
      .Subscribe(e => d.Dispose()); 
     d.Add(d2); 
     d.Add(d3); 
    } 

    // Where your bindings are simply yielded and 
    // they are removed on Unload magically 
    IEnumerable<IDisposable> CreateBindings() 
    { 
     // When the size changes we need to update all the transforms on 
     // the markers to reposition them. 
     yield return this.SizeChangedObserver() 
      .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler) 
      .Subscribe(eventArgs => this.ResetImageSource()); 

     // If the points change or the viewport changes 
     yield return this.WhenAny(t => t.Mesh, t => t.Viewport, (x, t) => x.Value) 
      .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler) 
      .Subscribe(t => this.UpdateMeshChanged()); 
    } 
} 

Nota sto avvolgendo RX FromEventPattern con generate automaticamente metodi di estensione in modo da ottenere SizeChangedObserver() e UnloadedObserver() per libero piuttosto che il formato difficile da ricordare di FromEventPattern.

Il codice di incarto viene generato come tale

public static IObservable<EventPattern<RoutedEventArgs>> UnloadedObserver(this FrameworkElement This){ 
    return Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(h => This.Unloaded += h, h => This.Unloaded -= h); 
} 

Il modello di cui sopra potrebbe probabilmente essere utilizzato per separare immagine modelli IDisposable pure.

Problemi correlati