2017-07-21 2 views
2

Je le morceau de code suivant:traitement d'interruption de l'élément en cours si de nouveaux éléments arrivent

 Observable.FromEventPattern<PropertyChangingEventArgs>(_parent, "PropertyChanged") 
      .Subscribe(ep => 
      { 
       switch (ep.EventArgs.PropertyName) 
       { 
        case "ValorBlurMenor": 
         LoadBlurMenor(); 
         break; 
        case "ValorBlurMaior": 
         LoadBlurMaior(); 
         break; 
       } 
      }); 

Mon problème est que ValorBlurMenor et ValorBlurMaior sont modifiés par curseurs WPF et LoadBlurMaior() et LoadBlurMenor() prendre un certain temps pour évaluer.

Je cherche un moyen d'interrompre/annuler l'exécution du délégué Subscribe pour un article si de nouveaux articles arrivent, donc effectuant toujours le traitement seulement sur le dernier article.

+0

Pouvez-vous s'il vous plaît préciser ce que vous entendez par "' LoadBlurMaior() 'et LoadBlurMenor()' prennent du temps pour évaluer "? Rx attendra toujours que le délégué d'abonnement précédent soit terminé avant de traiter la valeur suivante. Donc, à moins que vous ne vouliez dire que 'LoadBlurMaior()' et 'LoadBlurMenor()' déclenchent une sorte de comportement asynchrone, alors votre code devrait déjà faire ce que vous demandez. – Enigmativity

+0

@Enigmativity Merci pour votre intérêt. Lorsque je change une propriété dans ce viewmodel, via le curseur UI, je commence à déclencher certaines modifications qui sont effectuées par les méthodes 'LoadBlur **()'. Mais si, avant la fin de ce traitement, je finis par changer la valeur dans le curseur, je ne veux pas attendre que le traitement précédent soit terminé. Au lieu de cela, je veux traiter les dernières données tout de suite, en éliminant les progrès partiels des anciennes données. Je suppose que c'est plus ou moins ce que fait 'Observable.Switch'. – heltonbiker

+0

Quel "progrès partiel des anciennes données" est là? Rx n'a jamais de progrès partiel. Est-ce l'interface utilisateur qui a le progrès partiel? Si oui, alors c'est une question WPF et rien à voir avec Rx. – Enigmativity

Répondre

3

La façon la plus simple de le faire fonctionner est d'utiliser Observable.FromAsync<> surcharge qui utilise le CancellationToken et utiliser le jeton dans votre code pour vérifier fréquemment l'annulation:

public class PlainNotifiable : INotifyPropertyChanged 
{ 
    private bool takeFiveSeconds; 
    private bool takeTenSeconds; 
    public event PropertyChangedEventHandler PropertyChanged; 

    public bool TakeFiveSeconds 
    { 
     get => this.takeFiveSeconds; 
     set 
     { 
      this.takeFiveSeconds = value; 
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.TakeFiveSeconds))); 
     } 
    } 
    public bool TakeTenSeconds 
    { 
     get => this.takeTenSeconds; 
     set 
     { 
      this.takeTenSeconds = value; 
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.TakeTenSeconds))); 
     } 
    } 

    public async Task TakeSomeTime(int seconds, CancellationToken token = default(CancellationToken)) 
    { 
     Trace.TraceInformation("Started waiting {0} seconds", seconds); 
     await Task.Delay(seconds * 1000, token); 
     Trace.TraceInformation("Stoped waiting {0} seconds", seconds); 

    } 
} 
public static async void Test() 
{ 
    var test = new PlainNotifiable(); 
    async Task<Unit> propertyNameToLongTask(EventPattern<PropertyChangedEventArgs> args, CancellationToken token) 
    { 
     switch (args.EventArgs.PropertyName) 
     { 
      case nameof(test.TakeFiveSeconds): 
       await test.TakeSomeTime(5, token); 
       break; 

      case nameof(test.TakeTenSeconds): 
       await test.TakeSomeTime(10, token); 
       break; 
     } 
     return Unit.Default; 

    } 

    Observable.FromEventPattern<PropertyChangedEventArgs>(test, nameof(test.PropertyChanged)) 
     .Select(x => Observable.FromAsync(token => propertyNameToLongTask(x, token))) 
     .Switch() 
     .Subscribe(x => Trace.TraceInformation("Beep boop")); 

    Trace.TraceInformation("Started sending notifications"); 
    await Task.Delay(1000); 
    test.TakeTenSeconds = true; 
    await Task.Delay(2000); 
    test.TakeFiveSeconds = true; 
    Trace.TraceInformation("Finished sending notifications"); 

} 

Il donne le résultat suivant:

SandBox.exe Information: 0 : Started sending notifications 
SandBox.exe Information: 0 : Started waiting 10 seconds 
SandBox.exe Information: 0 : Started waiting 5 seconds 
SandBox.exe Information: 0 : Finished sending notifications 
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in mscorlib.dll 
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in mscorlib.dll 
SandBox.exe Information: 0 : Stoped waiting 5 seconds 
SandBox.exe Information: 0 : Beep boop 

Points clés sont les suivants:

  • Observable.FromAsync(): C réer une observable avec un support CancellationToken correct
  • Switch(): Flatenize en ne souscrivant à la dernière observable, elle aussi bien disposer l'observable précédent en utilisant, dans ce cas, le CancellationToken