2017-07-17 78 views
7

的長期反應鏈的建立目前,我有接收/ ReactiveUI以下代碼塊:如何封裝觀測

 this.WhenAnyValue(x => x.Listras) 
      .Where(item => item != null) 
      .Throttle(TimeSpan.FromMilliseconds(millis)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(im => GetArray.FromChannels(im, 0, 1)) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .ToProperty(this, x => x.Grayscale, out _grayscale); 

     this.WhenAnyValue(x => x.Grayscale) 
      .Where(item => item != null) 
      .Throttle(TimeSpan.FromMilliseconds(millis)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(ar => Gaussian.GaussianConvolution(ar, 1.5)) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .ToProperty(this, x => x.BlurMenor, out _blurMenor); 

     this.WhenAnyValue(x => x.BlurMenor) 
      .Where(item => item != null) 
      .Throttle(TimeSpan.FromMilliseconds(millis)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; }) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .ToProperty(this, x => x.ImagemBlurMenor, out _imagemBlurMenor); 

     this.WhenAnyValue(x => x.BlurMenor) 
      .Where(item => item != null) 
      .Throttle(TimeSpan.FromMilliseconds(millis)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(ar => Gaussian.VerticalGaussianConvolution(ar, 5)) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .ToProperty(this, x => x.BlurMaior, out _blurMaior); 

     this.WhenAnyValue(x => x.BlurMaior) 
      .Where(item => item != null) 
      .Throttle(TimeSpan.FromMilliseconds(millis)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; }) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .ToProperty(this, x => x.ImagemBlurMaior, out _imagemBlurMaior); 

     this.WhenAnyValue(x => x.BlurMenor, x => x.BlurMaior) 
      .Where(tuple => tuple.Item1 != null && tuple.Item2 != null) 
      .Throttle(TimeSpan.FromMilliseconds(millis)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(tuple => ArrayOperations.Diferença(tuple.Item1, tuple.Item2)) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .ToProperty(this, x => x.Diferença, out _diferença); 

     this.WhenAnyValue(x => x.Diferença) 
      .Where(item => item != null) 
      .Throttle(TimeSpan.FromMilliseconds(millis)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; }) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .ToProperty(this, x => x.ImagemDiferença, out _imagemDiferença); 

正如你所看到的,它公然違反了DRY原則,但我不知道如何我可以參數化傳遞屬性和代表。

在Rx/ReactiveUI中自動創建這些方法鏈的常用方法是什麼?

回答

8

Rx的美妙之處在於您可以根據其他操作員創建您自己的操作員。這是因爲Rx的功能方面。

您可以創建一個新的運營商,其封裝了所有常見的行爲,並採取小差異參數:

// Put this class somewhere useful. Either beside your VM inside the same namespace 
// Or in a seperate file for all your custom operators 
public static class ObservableMixins 
{ 
    public static IObservable<TOut> ThrottledSelect<TIn, TOut>(this IObservable<TIn> source, int milliseconds, Func<TIn, TOut> selector) => 
     source 
      .Where(item => item != null) 
      .Throttle(TimeSpan.FromMilliseconds(milliseconds)) 
      .ObserveOn(TaskPoolScheduler.Default) 
      .Select(selector) 
      .ObserveOn(RxApp.MainThreadScheduler) 
} 

使用這樣的:

this.WhenAnyValue(x => x.Listras) 
    .ThrottledSelect(millis, im => GetArray.FromChannels(im, 0, 1)) 
    .ToProperty(this, x => x.Grayscale, out _grayscale); 

this.WhenAnyValue(x => x.Grayscale) 
    .ThrottledSelect(millis, ar => Gaussian.GaussianConvolution(ar, 1.5)) 
    .ToProperty(this, x => x.BlurMenor, out _blurMenor); 

this.WhenAnyValue(x => x.BlurMenor) 
    .ThrottledSelect(millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; }) 
    .ToProperty(this, x => x.ImagemBlurMenor, out _imagemBlurMenor); 

this.WhenAnyValue(x => x.BlurMenor) 
    .ThrottledSelect(millis, ar => Gaussian.VerticalGaussianConvolution(ar, 5)) 
    .ToProperty(this, x => x.BlurMaior, out _blurMaior); 

this.WhenAnyValue(x => x.BlurMaior) 
    .ThrottledSelect(millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; }) 
    .ToProperty(this, x => x.ImagemBlurMaior, out _imagemBlurMaior); 

this.WhenAnyValue(x => x.BlurMenor, x => x.BlurMaior) 
    // Notice how I'm returning a null if either item is null 
    // It will be filtered in the operator 
    .Select(tuple => tuple.Item1 != null || tuple.Item2 != null ? null : tuple) 
    .ThrottledSelect(millis, tuple => ArrayOperations.Diferença(tuple.Item1, tuple.Item2)) 
    .ToProperty(this, x => x.Diferença, out _diferença); 

this.WhenAnyValue(x => x.Diferença) 
    .ThrottledSelect(millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; }) 
    .ToProperty(this, x => x.ImagemDiferença, out _imagemDiferença); 

如果你感覺少一點冒險,你當然可以用它作爲一個可觀察的常規方法:

public IObservable<T> ThrottledSelect<TIn, TOut>(IObservable<TIn> source, int milliseconds, Func<TIn, TOut> selector) => 
    source 
     .Where(item => item != null) 
     .Throttle(TimeSpan.FromMilliseconds(milliseconds)) 
     .ObserveOn(TaskPoolScheduler.Default) 
     .Select(selector) 
     .ObserveOn(RxApp.MainThreadScheduler) 

並使用它:

ThrottledSelect(this.WhenAnyValue(x => x.Diferença), millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; }) 
    .ToProperty(this, x => x.ImagemDiferença, out _imagemDiferença);