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
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
@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
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