如果新物品到达,则中断当前物品的处理

时间:2017-07-21 14:37:11

标签: c# wpf system.reactive reactive-programming

我有以下代码:

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

我的问题是ValorBlurMenorValorBlurMaior是通过WPF滑块更改的,LoadBlurMaior()LoadBlurMenor()需要一些时间来评估。

如果新项目到达,我正在寻找一种方法来中断/取消项目的Subscribe代表的执行,因此始终只对最后一项执行处理。

1 个答案:

答案 0 :(得分:3)

让它运行的最简单方法是使用Observable.FromAsync<>重载使用CancellationToken并使用代码中的令牌来经常检查取消:

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");

}

它提供以下输出:

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

要点是:

  • Observable.FromAsync():使用正确的CancellationToken支持
  • 创建一个observable
  • Switch():仅通过订阅最新的observable进行Flatenize,它还使用属性处理前一个observable,在本例中为CancellationToken