How do you update the CanExecute value after the ReactiveCommand has been declared - mvvm

I am using ReactiveUI with AvaloniaUI and have a ViewModel with several ReactiveCommands namely Scan, Load, and Run.
Scan is invoked when an Observable<string> is updated (when I receive a barcode from a scanner).
Load is triggered from within the Scan command.
Run is triggered from a button on the UI.
Simplified code below:
var canRun = Events.ToObservableChangeSet().AutoRefresh().ToCollection().Select(x => x.Any());
Run = ReactiveCommand.CreateFromTask<bool>(EventSuite.RunAsync, canRun);
var canLoad = Run.IsExecuting.Select(x => x == false);
var Load = ReactiveCommand.CreateFromTask<string, Unit>(async (barcode) =>
{
//await - go off and load Events.
}, canLoad);
var canReceiveScan = Load.IsExecuting.Select(x => x == false)
.Merge(Run.IsExecuting.Select(x => x == false));
var Scan = ReactiveCommand.CreateFromTask<string, Unit>(async (barcode) =>
{
//do some validation stuff
await Load.Execute(barcode)
}, canReceiveScan);
Barcode
.SubscribeOn(RxApp.TaskpoolScheduler)
.ObserveOn(RxApp.MainThreadScheduler)
.InvokeCommand(Scan);
Each command can only be executed if no other command is running (including itself). But I can't reference the commands' IsExecuting property before is it declared. So I have been trying to merge the "CanExecute" observable variables like so:
canRun = canRun
.Merge(Run.IsExecuting.Select(x => x == false))
.Merge(Load.IsExecuting.Select(x => x == false))
.Merge(Scan.IsExecuting.Select(x => x == false))
.ObserveOn(RxApp.MainThreadScheduler);
// same for canLoad and canScan
The issue I'm having is that the ReactiveCommand will continue to execute when another command is executing.
Is there a better/correct way to implement this?

But I can't reference the commands' IsExecuting property before is it declared.
One option is to use a Subject<T>, pass it as the canExecute: parameter to the command, and later emit new values using OnNext on the Subject<T>.
Another option is to use WhenAnyObservable:
this.WhenAnyObservable(x => x.Run.IsExecuting)
// Here we get IObservable<bool>,
// representing the current execution
// state of the command.
.Select(executing => !executing)
Then, you can apply the Merge operator to the observables generated by WhenAnyObservable. To skip initial null values, if any, use either the Where operator or .Skip(1).

To give an example of the Subject<T> option described in the answer by Artyom, here is something inspired by Kent Boogaart's book p. 82:
var canRun = new BehaviorSubject<bool>(true);
Run = ReactiveCommand.Create...(..., canExecute: canRun);
Load = ReactiveCommand.Create...(..., canExecute: canRun);
Scan = ReactiveCommand.Create...(..., canExecute: canRun);
Observable.Merge(Run.IsExecuting, Load.IsExecuting, Scan.IsExecuting)
.Select(executing => !executing).Subscribe(canRun);

Related

Using Reactive to sum the certain sections of Observable

I am trying to use reactive operators to find individual sum of the values emitted by the observable. The end goal is to emit individual sums. The sequence looks something like this. The ones I want to add up are occuring as continuous groups (of varying length) with varying frequency in between the values I want to discard. The ones I want to add have a field which is of type bool and has value true.
-(F,2)-(T,4)-(T,2)-(T,7)-(F,8)-(F,9)-(F,1)-(T,2)-(T,1)-(F,1)-
What have I tried so far:
myObservable.
.Where(x => x.IsItUseful == true)
.Aggregate(0.0, (sum,currentItem) => sum + currentItem.Value)
.Subscribe("NotYet")
This one give back the sum of ALL elements which have been marked as true.
myObservable
.SkipWhile(x => x.IsItUseful == false)
.TakeWhile(x => x.IsItUseful == true)
.Aggregate(0.0, (sum, currentItem) => sum + currentItem.Item3)
.Subscribe("NotYetAgain");
This one gives the sum of the first group only.
Right now I am trying along these lines.
myObservable
.Buffer(myObservable.DistinctUntilChanged(x => x.IsItUseful => true)
.Subscribe("NotSure")
I am still hazy on on BufferBoundary and BufferClosingSelector. I think a new buffer will open once I process a group of valid values. And this new buffer will have values from that point on wards till the end of another valid group. This means that I will pick up some not valid values too before the second group. I haven't been able to find some examples on Buffer with both open and close options getting used. Not sure if this is right approach too.
The final option is that I write an extension method on Buffer and put my custom logic there. But if there is an out of box solution I will prefer that.
There's two primary approaches I would recommend here. One uses Scan, the other uses Buffer/Window. Both of them have edge case problems that are solvable, but need clarity on the problem side.
Here's the Scan solution:
var result = source
.Scan((0, true), (state, value) => (value.IsItUseful ? state.Item1 + value.Value : 0, value.IsItUseful))
.Publish(_tuples =>
_tuples.Zip(_tuples.Skip(1), (oldTuple, newTuple) => (oldTuple, newTuple))
)
.Where(t => t.oldTuple.Item2 == true && t.newTuple.Item2 == false)
.Select(t => t.oldTuple.Item1);
Scan is similar to Aggregate, just more useful: Aggregate will only dump out one value at the end; whereas Scan emits intermediate values. So we track the running sum in there, resetting to 0 when we see a false. The next step (Zip) combines the latest message with its predecessor, so we can figure out whether or not we have to emit: We want to emit if the new flag value is false, but the old flag value is true. We then emit the old sum.
There's an edge case problem here if the last flag value is true: I'm assuming you want to emit on the OnCompleted, but that won't currently happen. Please clarify if that's needed.
Here's the Window solution:
var result2 = source
.Publish(_values => _values
.Window(_values.Select(v => v.IsItUseful).DistinctUntilChanged().Where(b => b == false))
)
.SelectMany(o => o.Where(a => a.IsItUseful).Sum(a => a.Value));
Window by the distinctly new falses, then sum them, similar to what you proposed.
The edge case problem here is that you end up with a leading and tailing 0 if you begin/end with falses (as your sample set does). Removing those would require some clean up as well.
FYI: Window and Buffer are practically the same: They have the same overloads and each group values into "windows". Window returns them as an observable stream, and Buffer holds them into a list which returns when the window closes. For more look here.
Here's runner code if anybody else wants to test this:
public class Message
{
public Message(bool b, int v)
{
IsItUseful = b;
Value = v;
}
public bool IsItUseful { get; set; }
public int Value { get; set; }
}
var values = new List<Message>
{
new Message(false, 2),
new Message(true, 4),
new Message(true, 2),
new Message(true, 7),
new Message(false, 8),
new Message(false, 9),
new Message(false, 1),
new Message(true, 2),
new Message(true, 1),
new Message(false, 1),
};
var source = values.ToObservable();
var result = source
.Scan((0, true), (state, value) => (value.IsItUseful ? state.Item1 + value.Value : 0, value.IsItUseful))
.Publish(_tuples =>
_tuples.Zip(_tuples.Skip(1), (oldTuple, newTuple) => (oldTuple, newTuple))
)
.Where(t => t.oldTuple.Item2 == true && t.newTuple.Item2 == false)
.Select(t => t.oldTuple.Item1);
var result2 = source
.Publish(_values => _values
.Buffer(_values.Select(v => v.IsItUseful).DistinctUntilChanged().Where(b => b == false))
)
.Select(o => o.Where(a => a.IsItUseful).Sum(a => a.Value));
result.Dump(); //Linqpad
result2.Dump(); //Linqpad

Howto loop OrderedAssertions in FakeItEasy 2

As I understand, ordered assertions in FakeItEasy 2 are done like this (from the docs):
// Assert
A.CallTo(() => unitOfWorkFactory.BeginWork()).MustHaveHappened()
.Then(A.CallTo(() => usefulCollaborator.JustDoIt()).MustHaveHappened())
.Then(A.CallTo(() => unitOfWork.Dispose()).MustHaveHappened());
Now, suppose I have a collection and for each item in this collection I want to assert that a call was made to a faked object. What is the best approach to assert the calls were made in the correct order?
I came up with this, but don't really like it:
IOrderableCallAssertion ioca = null;
foreach (var item in items.OrderBy(i => i.Id)
{
var itemUnderTest = item;
if (ioca == null)
{
ioca = A.CallTo(() => fakeObject.Handle(itemUnderTest, otherArgument)).MustHaveHappened(Repeated.Exactly.Once);
}
else
{
ioca = ioca.Then(A.CallTo(() => fakeObject.Handle(itemUnderTest, otherArgument)).MustHaveHappened(Repeated.Exactly.Once));
}
}
That looks about right to me. Of course, you could inline itemUnderTest and pull MustHaveHappened outside of the two if branches.
And you could always hide this in a convenience method.
An alternative: use Invokes to capture the fakes as the calls come in and later compare them against a list.

Reactive Extension key press media controls

I have a media application that allows the user to Play, Pause, step frame by frame, FastForward, etc. I am attempting to use Rx to get the following behavior for stepping and FastForward.
If the user clicks the right arrow less than 2 times/300ms I want to frame step.
If the user holds down the right arrow I want to fast forward until the right arrow button is released.
I think I have the fast forward part correct, but am not sure how to craft this to get the step functionality. I am also open to "better" ways to do the fast forward.
//start FF when we get 2 key presses within the threshold time
Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown")
.Where(k => k.EventArgs.Key == Key.Right)
.Timestamp()
.Buffer(2)
.Where(x => (x[1].Timestamp - x[0].Timestamp).Milliseconds < 300)
.Subscribe(x =>
{
Console.WriteLine("FastForward GO");
_viewModel.FastForward();
});
//stop ff on the key up
Observable.FromEventPattern<KeyEventArgs>(this, "KeyUp")
.Where(k => k.EventArgs.Key == Key.Right)
.Subscribe(x => {
Console.WriteLine("FastForward STOP");
_viewModel.StopFastForward();
});
Solution
var up = Observable.FromEventPattern<KeyEventArgs>(this, "KeyUp")
.Where(x => x.EventArgs.KeyCode == Keys.Right);
// Take, Concat, and Repeat work together to prevent repeated KeyDown events.
var down = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown")
.Where(x => x.EventArgs.KeyCode == Keys.Right)
.Take(1)
.Concat(up.Take(1).IgnoreElements())
.Repeat();
var t = TimeSpan.FromMilliseconds(300);
var tap = down.SelectMany(x =>
Observable.Amb(
Observable.Empty<EventPattern<KeyEventArgs>>().Delay(t),
up.Take(1)
))
.Publish()
.RefCount();
var longPress = down.SelectMany(x =>
Observable.Return(x).Delay(t).TakeUntil(tap)
);
There's multiple ways to do this, but this works at getting the "longPress" you need, as well as the "tap". You can use longPress to start fast-fowarding, up to stop fast-forwarding, and tap for frame-stepping.
tap yields when a key has been pressed and released within a timespan of t.
longPress yields when the key has been held down for longer than t.
up yields when the key has been released.
Explaination
A problem exists because the KeyDown event is repeated multiple times for each physical press of a key.
var down = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown");
In this case, we need a way to filter out the repeated KeyDown events. We can do that by using a combination of operators. First, we'll use Take(1). This will yield the first event and ignore the rest.
var first = down.Take(1);
If we only needed to get a single actual key press, this would be great. But, alas, we need to get all of the actual key presses. We need to wait for the KeyUp event to occur and start the whole thing over. To do this, we can use a combination of Concat and Repeat. For the concat observable, we need to make sure we're only taking 1 up event, and that we're ignore the elements of the up observable, otherwise we end up feeding all of the up events into our new observable.
var down = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown")
.Take(1)
.Contact(up.Take(1).IgnoreElements())
.Repeat();
This gives us the actual down events, without the in-between repeated events.
Now that we've cleaned up our source observables, we can start composing them in useful ways. What we're looking for is a "tap" event and a "long press" event. To get the tap event, we need to take a single actual down event, and make sure that it isn't held down too long... One way to do this is using the Amb operator.
var tap = down.SelectMany(x =>
Observable.Amb(
Observable.Empty<EventPattern<KeyEventArgs>>().Delay(t),
up.Take(1)
))
The Amb operator stands for "ambiguous". It takes a number of Observables, listens to each one, and waits for them to yield something. Once one of them yields an event, the Amb operator ignores (disposes the subscriptions of) the other observables.
In our case, for each down event that occurs, we use the SelectMany and Amb operator to check to see which yields or completes first... a single up event, or an empty observable that completes after a timespan of t. If the up event occurs before the the empty observable completes, its a tap. Otherwise, we ignore it.
Now we can do a similar thing for "long press", except this time we want to delay the KeyDown event until we know that it's not a tap. We can use a combination of the Delay and TakeUntil operators to do this. Delay makes sure the long press doesn't occur before a tap can be registered, and TakeUntil makes sure we ignore the KeyPress if it turned out to be a tap after all.
var longPress = down.SelectMany(x =>
Observable.Return(x).Delay(t).TakeUntil(tap)
);
Generalized Solution
This version works for any key.
var up = Observable.FromEventPattern<KeyEventArgs>(this, "KeyUp");
var downWithRepeats = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown");
var down =
Observable.Merge(
up.Select(x => new { e = x, type = "KeyUp" }),
downWithRepeats.Select(x => new { e = x, type = "KeyDown" })
)
.GroupByUntil(
x => x.e.EventArgs.KeyCode,
g => g.Where(y => y.type == "KeyUp")
)
.SelectMany(x => x.FirstAsync())
.Select(x => x.e);
var t = TimeSpan.FromMilliseconds(300);
var tap = down.SelectMany(x =>
Observable.Amb(
Observable.Empty<EventPattern<KeyEventArgs>>().Delay(t),
up.Where(y => y.EventArgs.KeyCode == x.EventArgs.KeyCode).Take(1)
))
.Publish()
.RefCount();
var longPress = down.SelectMany(x =>
Observable.Return(x).Delay(t).TakeUntil(
tap.Where(y => y.EventArgs.KeyCode == x.EventArgs.KeyCode)
)
);
Usage
Observable.Merge(
down .Select(x => string.Format("{0} - press", x.EventArgs.KeyCode)),
tap .Select(x => string.Format("{0} - tap", x.EventArgs.KeyCode)),
longPress.Select(x => string.Format("{0} - longPress", x.EventArgs.KeyCode)),
up .Select(x => string.Format("{0} - up", x.EventArgs.KeyCode))
)
.ObserveOn(SynchronizationContext.Current)
.Select(x => string.Format("{0} - {1}", x, DateTime.Now.ToLongTimeString()))
.Subscribe(text => this.myTextBox.Text = text);
Here's an alternative to Chris's that gives three streams, one for clicks, one for begin holds and one for end holds. Makes use of TimeInterval for recording duration between events.
WinForms Version
We can capture KeyDown eliminating repeats by using GroupByUntil to group KeyDown until a KeyUp occurs:
TimeSpan limit = TimeSpan.FromMilliseconds(300);
var key = Keys.Right;
var keyUp = Observable.FromEventPattern<KeyEventArgs>(this, "KeyUp")
.Where(i => i.EventArgs.KeyCode == key)
.Select(_ => true);
var keyDown = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown")
.Where(i => i.EventArgs.KeyCode == key)
.GroupByUntil(k => 0, _ => keyUp)
.SelectMany(x => x.FirstAsync());
var keyDownDuration = keyDown.Select(k => keyUp.TimeInterval()).Switch();
var clicks = keyDownDuration.Where(i => i.Interval < limit);
var beginHold = keyDown.Select(k => Observable.Timer(limit).TakeUntil(keyUp))
.Switch();
var endHold = keyDownDuration.Where(i => i.Interval > limit);
/* usage */
clicks.Subscribe(_ => Console.WriteLine("Click"));
beginHold.Subscribe(_ => Console.WriteLine("Hold Begin"));
endHold.Subscribe(_ => Console.WriteLine("Hold End"));
WPF Version
Originally, I had mistakenly assumed the WPF flavour of KevEventArgs as IsRepeat is not available in the WinForms version - which means this won't work for OP, but I'll leave it in as it may be of use for others.
TimeSpan limit = TimeSpan.FromMilliseconds(300);
var key = Key.Right;
var keyUp = Observable.FromEventPattern<KeyEventArgs>(this, "KeyUp")
.Where(i => i.EventArgs.Key == key);
var keyDown = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown")
.Where(i => i.EventArgs.IsRepeat == false
&& i.EventArgs.Key == key);
var keyDownDuration = keyDown.Select(k => keyUp.TimeInterval()).Switch();
var clicks = keyDownDuration.Where(i => i.Interval < limit);
var beginHold = keyDown.Select(k => Observable.Timer(limit).TakeUntil(keyUp))
.Switch();
var endHold = keyDownDuration.Where(i => i.Interval > limit);
/* usage */
clicks.Subscribe(_ => Console.WriteLine("Click"));
beginHold.Subscribe(_ => Console.WriteLine("Hold Begin"));
endHold.Subscribe(_ => Console.WriteLine("Hold End"));
To Test The Code
Include nuget package rx-main and paste the WinForms/WPF or code snippets as appropriate to the end of the Form contructor. Then run the code and press the right arrow key whilst observing the VS Output window to see the result.

RX PropertyChanged GroupBy deadlock

I am trying to use Reactive Extensions to throttle PropertyChanged notifications. There are examples of doing this using GroupBy, but with one Subscription created for each PropertyName.
I want to handle the PropertyChanged event for all properties, and I need to Throttle those events for each PropertyName.
This is what I have so far, but it causes a deadlock.
ValuesPropertyChanged = Observable.FromEventPattern<PropertyChangedEventArgs>(value, "PropertyChanged")
.GroupBy(o => o.EventArgs.PropertyName)
.First()
.Throttle(TimeSpan.FromSeconds(2))
.Subscribe(args => HandlePropertyChanged(args.EventArgs.PropertyName));
The deadlock happens in the call to .First().
It still locks if I change that line to:
.Select(o => o.First())
I have also tried
.Select(o => o.FirstAsync())
The examples for GroupBy here look pretty concise, but I am incapable of wrapping my head around converting these examples to my solution.
Why does this cause a deadlock, and what should I do to make this work?
I think this might be what you're after:
// assume MyObj : INotifyPropertyChanged, naturally
var value = new MyObj();
Action<string> HandlePropertyChanged =
name => Console.WriteLine("Got a change for name:" + name);
// The query
var valuesPropertyChanged =
// create from event stream
from propChange in Observable.FromEventPattern<PropertyChangedEventArgs>(
value,
"PropertyChanged")
// group events by property name
group propChange by propChange.EventArgs.PropertyName into batchByName
// Throttle the resulting batch
from throttledByName in batchByName.Throttle(TimeSpan.FromSeconds(1))
// then select each item of the "throttled output"
select throttledByName;
valuesPropertyChanged.Subscribe(args =>
HandlePropertyChanged(args.EventArgs.PropertyName));
for(int i=0;i<10;i++)
{
value.Value1 = i.ToString();
value.Value2 = (i-1).ToString();
}
Output:
Got a change for name:Value2
Got a change for name:Value1
Here is the same but with extension methods:
var valuesPropertyChanged =
Observable.FromEventPattern<PropertyChangedEventArgs>(
_vm,
"PropertyChanged")
.GroupBy(propchange => propchange.EventArgs.PropertyName)
.Select(o => o.Throttle(TimeSpan.FromSeconds(1)))
.Merge();

Neater way to switch between two IObservables based on a third

I have two value streams and one selector stream and I'd like to produce a result stream that alternates between the value streams based on the selector. The code below gives the right result, but I don't like it.
Does anyone have anything neater?
var valueStreamA = new BehaviorSubject<int>(0);
var valueStreamB = new BehaviorSubject<int>(100);
var selectorStream = new BehaviorSubject<bool>(true);
var filteredA = valueStreamA .CombineLatest(selectorStream, (a, c) => new { A = a, C = c })
.Where(ac => ac.C)
.Select(ac => ac.A);
var filteredB = valueStreamB.CombineLatest(selectorStream, (b, c) => new { B = b, C = c })
.Where(bc => !bc.C)
.Select(bc => bc.B);
var result = Observable.Merge(filteredA, filteredB);
result.Subscribe(Console.WriteLine);
valueStreamA.OnNext(1);
valueStreamB.OnNext(101);
selectorStream.OnNext(false);
valueStreamA.OnNext(2);
valueStreamB.OnNext(102);
selectorStream.OnNext(true);
This productes the following output:
0
1
101
102
2
I'd do something like this:
var a = new BehaviorSubject<int>(0);
var b = new BehaviorSubject<int>(100);
var c = new BehaviorSubject<bool>(true);
var valueStreamA = a as IObservable<int>;
var valueStreamB = b as IObservable<int>;
var selector = c as IObservable<bool>;
var result = selector
// for every change in the selector...
.DistinctUntilChanged()
// select one of the two value streams
.Select(change => change ? valueStreamA : valueStreamB)
// and flatten the resulting wrapped observable
.Switch();
result.Subscribe(Console.WriteLine);
a.OnNext(1);
b.OnNext(101);
c.OnNext(false);
a.OnNext(2);
b.OnNext(102);
c.OnNext(true);
Could do something like:
var xs = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => Feeds.Xs);
var ys = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => Feeds.Ys);
var selectorSubject = new Subject<Feeds>();
var query = from selector in selectorSubject
select from merged in xs.Merge(ys)
where merged == selector
select merged;
query.Switch().Subscribe(Console.WriteLine);
OnNext into your 'selectorSubject' to change it.
There are a few differences to your example, but easy to get around:
Your question involved a selector of type bool, whereas I have been lazy and reused the Feeds enum in order to allow me to do an easy equality check (where merged == selector).
You of course could simply do (where selector ? merged == Xs : merged == Ys), or something like that to evaluate each merged item and discard ones you don't care about (depending on your selector).
Specifically, you would probably want to select not just the integer, but an identifier of the feed. Consider using something like Tuple.Create(), so you get that info with each update:
{A - 1}, {B - 101} etc. Your where can then do:
where selector ? merged.Item1 == A : merged.Item1 == B //this maps 'true' to feed A
I also used a Switch, which will cause my sample streams to restart because they are not published.
You probably want to publish yours and Connect them (make them 'hot'), so a Switch like mine doesn't cause any new side effects in the subscription. You have a subject (which is hot), but the 'behaviour' part will replace the value you passed into the constructor. Publishing and connecting would prevent that.
Shout if you are still confused. This isn't a full answer, but might give you enough to think about.
Howard.
Now much closer to your original question:
void Main()
{
var valueStreamA = new BehaviorSubject<int>(0);
var valueStreamB = new BehaviorSubject<int>(100);
var selectorStreamA = valueStreamA.Select(id => Tuple.Create("A", id)).Publish();
var selectorStreamB = valueStreamB.Select(id => Tuple.Create("B", id)).Publish();
var selectorStream = new BehaviorSubject<bool>(true);
var query = from selector in selectorStream
select from merged in selectorStreamA.Merge(selectorStreamB)
where selector == true ? merged.Item1 == "A" : merged.Item1 == "B"
select merged.Item2;
query.Switch().Subscribe(Console.WriteLine);
selectorStreamA.Connect();
selectorStreamB.Connect();
//First we get 0 output (because we are already using stream A, and it has a first value)
valueStreamA.OnNext(1); //This is output, because our selector remains as 'A'
valueStreamB.OnNext(101); //This is ignored - because we don't take from B
selectorStream.OnNext(false); //Switch to B
valueStreamA.OnNext(2); //Ignored - we are now using B only
valueStreamB.OnNext(102); //This is output
selectorStream.OnNext(true); //Switch back to A.
}
Outputs:
0
1
102