如何在一个可观察对象上使用触发器来抑制另一个对象的触发器?
How to use trigger on one observable to suppress trigger on another?
假设我有两个可观察对象 Obs1 和 Obs2。我想要 Obs1 上的触发器来抑制 Obs2 上的后续触发器(下面的大理石图)。我该怎么做?
Obs1---x---x--x----
Obs2----yyy-yy-yyyy
Rslt-----yy--y--yyy
具体来说,我有一个 class 具有两个属性,Target 和 SelectedItem。设置目标后,应立即根据目标上的 SpecialValue 属性 设置 SelectedItem。用户应该能够更改选择,在这种情况下,新值会传播回目标。仅当用户更改值时,SelectedItem 才应传播回目标;但是,在设置目标的那一刻,该值就会传播回目标 - 这是我正在尝试修复的不良行为。
(SelectionViewModel 利用了 ReactiveUI,但我们模仿了 Prism 的 SetProperty 方法来帮助迁移。BindToProperty 只是一个辅助方法,它按照它说的去做。)
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); }
}
}
看来您要做的是破译 SelectedItem
是由 IObservable
还是用户设置的。我想知道共享状态的一种方法是使用标志来通知 SelectedItem
是否被 Target
对象中的更改或用户更改,所以:
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); }
}
}
这个解决方案使用了副作用诱导 .Do
这不是好的做法,因为副作用很糟糕!
这会生成您想要的值:
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");
我得到:
Y1
Y2
Y4
Y6
Y7
Y8
假设我有两个可观察对象 Obs1 和 Obs2。我想要 Obs1 上的触发器来抑制 Obs2 上的后续触发器(下面的大理石图)。我该怎么做?
Obs1---x---x--x----
Obs2----yyy-yy-yyyy
Rslt-----yy--y--yyy
具体来说,我有一个 class 具有两个属性,Target 和 SelectedItem。设置目标后,应立即根据目标上的 SpecialValue 属性 设置 SelectedItem。用户应该能够更改选择,在这种情况下,新值会传播回目标。仅当用户更改值时,SelectedItem 才应传播回目标;但是,在设置目标的那一刻,该值就会传播回目标 - 这是我正在尝试修复的不良行为。
(SelectionViewModel 利用了 ReactiveUI,但我们模仿了 Prism 的 SetProperty 方法来帮助迁移。BindToProperty 只是一个辅助方法,它按照它说的去做。)
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); }
}
}
看来您要做的是破译 SelectedItem
是由 IObservable
还是用户设置的。我想知道共享状态的一种方法是使用标志来通知 SelectedItem
是否被 Target
对象中的更改或用户更改,所以:
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); }
}
}
这个解决方案使用了副作用诱导 .Do
这不是好的做法,因为副作用很糟糕!
这会生成您想要的值:
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");
我得到:
Y1 Y2 Y4 Y6 Y7 Y8