Combining Multiple Events in RX
I have 2 touch enabled Canvas' in a Silverlight App. What I need to do is when a person Holds (presses and keeps pressing) both canvases at the same time increment a value on the screen once. This should happen for every "double" hold. I can do that fine using normal events but tried writing the same thing using RX and I am getting stuck.
Currently my code looks identical to the separate events approach (using global variables and global method) but I think there must be a better way to compose this. Can anyone suggest a better approach?
var leftHold = Observable.FromEvent<TCanvas.HoldHandler, GestureHoldEventArgs>(
h => new TCanvas.HoldHandler(h),
h => HoldLeft.Hold += h,
h => HoldLeft.Hold += h
);
var rightHold = Observable.FromEvent<TCanvas.HoldHandler, GestureHoldEventArgs>(
h => new TCanvas.HoldHandler(h),
h => HoldRight.Hold += h,
h => HoldRight.Hold += h
);
var rightRelease = Observable.FromEvent<TCanvas.ReleaseHandler, EventArgs>(
h => new TCanvas.ReleaseHandler(e => { }),
h => HoldRight.Release += h,
h => HoldRight.Release += h
);
var leftRelease = Observable.FromEvent<TCanvas.ReleaseHandler, EventArgs>(
h => new TCanvas.ReleaseHandler(e => { }),
h => HoldLeft.Release += h,
h => HoldLeft.Release += h
);
leftHold.Subscribe(e =>
{
_leftHeld = true;
DoCheck();
});
rightHold.Subscribe(e =>
{
_rightHeld = true;
DoCheck();
});
rightRelease.Subscribe(e =>
{
_rightHeld = false;
DoCheck();
});
leftRelease.Subscribe(e =>
{
_leftHeld = false;
DoCheck();
});
And the very basic DoCheck function looks like this....
private void DoCheck()
{
if (_rightHeld && _leftHeld)
{
MyTextBox.Text = (Convert.ToInt32(MyTextBox.Text) + 1).ToString() ;
}
}
Hopefully you can see what I am trying to do. Each canvas has a hold and release event so 开发者_如何学编程when HoldLeft and HoldRight are both held do something until either HoldRight or HoldLeft are is released.
Any help would be appreciated.
I believe I have solved my own problem.
Rather than the multiple subscribes I went for this.
leftHold.Zip(rightHold, (a,b) => true)
.TakeUntil(leftRelease.Amb(rightRelease))
.Subscribe(_ => TextOutput.Text = (Convert.ToInt32(TextOutput.Text) + 1).ToString());
It appears to do what I want but I am open to further suggestions/improvements.
I came across this answer and thought that it didn't make sense:
leftHold.Zip(rightHold, (a,b) => true)
.TakeUntil(leftRelease.Amb(rightRelease))
.Subscribe(_ => TextOutput.Text =
(Convert.ToInt32(TextOutput.Text) + 1).ToString());
Zip
pairs up events so would require that I release the left and the right before holding them again. If I released right and the held it again this observable wouldn't fire again.- I also would think that the hold
events only fire once, so there
shouldn't be any need for a
TakeUntil
call. - Also I don't see how this answer will refire - it seems to get only one value.
Here's an alternative:
var left = leftHold.Select(x => true).Merge(leftRelease.Select(x => false));
var right = rightHold.Select(x => true).Merge(rightRelease.Select(x => false));
var bothHold =
left.CombineLatest(right, (l, r) => l && r)
.Where(lr => lr == true)
.Select(lr => (Convert.ToInt32(MyTextBox.Text) + 1).ToString());
bothHold.Subscribe(t => MyTextBox.Text = t);
I know this question is a year old, but I would love to know if I've missed something or if this answer works.
精彩评论