2016-04-18 11 views
0

Nehmen wir an, ich habe zwei Observables Obs1 und Obs2. Ich möchte, dass ein Trigger auf Obs1 den nachfolgenden Trigger auf Obs2 unterdrückt (Marmordiagramm unten). Wie mache ich das?Wie Trigger auf einer Observable zu verwenden, um Trigger auf einem anderen zu unterdrücken?

Obs1---x---x--x---- 
Obs2----yyy-yy-yyyy 
Rslt-----yy--y--yyy 

Speziell habe ich eine Klasse mit zwei Eigenschaften, Target und SelectedItem. Wenn das Ziel festgelegt ist, sollte SelectedItem sofort basierend auf einer SpecialValue-Eigenschaft auf dem Ziel festgelegt werden. Benutzer sollten in der Lage sein, die Auswahl zu ändern. In diesem Fall wird der neue Wert an das Ziel weitergegeben. SelectedItem sollte nur dann zum Ziel zurückkehren, wenn der Benutzer den Wert ändert. Der Wert wird jedoch in dem Moment an das Ziel weitergegeben, an dem das Ziel festgelegt wurde. Dies ist das unerwünschte Verhalten, das ich beheben möchte.

(SelectionViewModel nutzt ReactiveUI, aber wir nachgeahmt SetProperty Methode des Prism in der Migration zu unterstützen. BindToProperty ist nur eine Hilfsmethode, die tut, was sie sagt.)

sealed class SelectionViewModel 
{ 
    internal SelectionViewModel() 
    { 
     this.WhenAnyValue(x => x.Target).Where(t => t != null) 
      .Select(_ => Target.SpecialValue) 
      .BindToProperty(this, x => x.SelectedItem); 

     this.WhenAnyValue(x => x.Target).Where(t => t != null) 
      .Select(_ => this.WhenAnyValue(x => x.SelectedItem).Skip(1)) 
      .Switch() 
      .BindToProperty(this, x => Target.SpecialValue); 
    } 

    private MyClass _selectedItem; 

    public MyClass SelectedItem 
    { 
     get { return _selectedItem; } 
     set { SetProperty(ref _selectedItem, value); } 
    } 

    private ITarget _target; 

    public ITarget Target 
    { 
     get { return _target; } 
     set { SetProperty(ref _target, value); } 
    } 
} 
+0

Im Interesse der Klarheit können Sie bitte Code für 'BindToProperty teilen()' – aateeque

+0

Es ist eine faire Anfrage, aber der Code ist ziemlich lang und ich denke, dass es als proprietär angesehen wird, also würden die Kräfte, die sein würden, wahrscheinlich meine Kniescheiben brechen, wenn ich es teilen würde. – ket

+0

Können Sie beschreiben, was es tut? Erzeugt es eine neue "Bindung" mit dem ersten Parameter als Quelle und dem zweiten als Ziel? – aateeque

Antwort

2

Daraus ergeben sich die Werte, die Sie wollen:

var Obs1 = new Subject<string>(); 
var Obs2 = new Subject<string>(); 

var query = Obs2.Publish(pobs2 => Obs1.Select(x => pobs2.Skip(1)).Switch()); 

query.Subscribe(Console.WriteLine); 

Obs1.OnNext("X0"); 
Obs2.OnNext("Y0"); 
Obs2.OnNext("Y1"); 
Obs2.OnNext("Y2"); 
Obs1.OnNext("X1"); 
Obs2.OnNext("Y3"); 
Obs2.OnNext("Y4"); 
Obs1.OnNext("X2"); 
Obs2.OnNext("Y5"); 
Obs2.OnNext("Y6"); 
Obs2.OnNext("Y7"); 
Obs2.OnNext("Y8"); 

ich:

 
Y1 
Y2 
Y4 
Y6 
Y7 
Y8 
+0

Perfekt, genau was ich brauchte. Vielen Dank! – ket

0

Es scheint, was Sie versuchen zu tun entschlüsseln, ob der SelectedItem durch den IObservable oder vom Benutzer eingestellt wird. Ob ein Weg, um den Zustand zu teilen, indem ein Flag zu benachrichtigen, ob die SelectedItem durch die Änderung, so dass in dem Target Objekt oder vom Benutzer geändert wird:

sealed class SelectionViewModel 
{ 
    private bool _setByTarget = false; 

    internal SelectionViewModel() 
    { 
     this.WhenAnyValue(x => x.Target).Where(t => t != null) 
      .Select(_ => Target.SpecialValue) 
      .Do(_ => _setByTarget = true) 
      .BindToProperty(this, x => x.SelectedItem); 

     this.WhenAnyValue(x => x.Target) 
      .Where(t => t != null && !_setByTarget) 
      .Select(_ => this.WhenAnyValue(x => x.SelectedItem)) 
      .Switch() 
      .BindToProperty(this, x => Target.SpecialValue); 

     this.WhenAnyValue(x => x.Target) 
      .Where(!_setByTarget) 
      .Subscribe(_ => _setByTarget = false); 
    } 

    private MyClass _selectedItem; 

    public MyClass SelectedItem 
    { 
     get { return _selectedItem; } 
     set { SetProperty(ref _selectedItem, value); } 
    } 

    private ITarget _target; 

    public ITarget Target 
    { 
     get { return _target; } 
     set { SetProperty(ref _target, value); } 
    } 
} 

Diese Lösung nutzt den Nebeneffekt Induktion .Do was nicht gut ist, weil die Nebenwirkungen schlecht sind!

+0

Interessant. Ich war mir der Do-Methode nicht bewusst (was bei den meisten Observable-Erweiterungsmethoden der Fall zu sein scheint). Ich könnte es versuchen - Nebenwirkungen schlagen nicht-Funktionalität! – ket

+0

Nachdem ich einen zweiten Gedanken gegeben habe, bin ich mir nicht sicher, dass es so funktionieren wird. weil es abhängt, in welcher Reihenfolge die Einstellung dieses Flags auftritt. Um zu kontrollieren, dass Sie ein "ObserveOn (EventLoopScheduler.Instance)" tun könnten - aber ich vermute, dass es eine elegantere Lösung zu diesem als das, was ich vorgeschlagen habe – aateeque

+0

gebe ich ein paar Tage, um zu sehen, ob jemand andere Ideen hat; Wenn nicht, gewinnst du! – ket