Объединение нескольких событий в RX
-
19-09-2019 - |
Вопрос
У меня есть Canvas с поддержкой 2 касаний в приложении Silverlight.Что мне нужно сделать, так это когда человек удерживает (нажимает и продолжает нажимать) оба полотна одновременно, увеличить значение на экране один раз.Это должно происходить при каждом "двойном" удержании.Я могу сделать это нормально, используя обычные события, но попытался написать то же самое с помощью RX, и я застрял.
В настоящее время мой код выглядит идентично подходу "отдельные события" (с использованием глобальных переменных и глобального метода), но я думаю, что должен быть лучший способ составить это.Кто-нибудь может предложить лучший подход?
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();
});
И самая базовая функция doCheck выглядит примерно так....
private void DoCheck()
{
if (_rightHeld && _leftHeld)
{
MyTextBox.Text = (Convert.ToInt32(MyTextBox.Text) + 1).ToString() ;
}
}
Надеюсь, вы понимаете, что я пытаюсь сделать.У каждого canvas есть событие hold и release, поэтому, когда HoldLeft и HoldRight оба удерживаются, делайте что-нибудь до тех пор, пока не будут освобождены либо HoldRight, либо HoldLeft are.
Будем признательны за любую помощь.
Решение
Я считаю, что решил свою проблему.
Вместо нескольких подписок я пошел на это.
leftHold.Zip(rightHold, (a,b) => true)
.TakeUntil(leftRelease.Amb(rightRelease))
.Subscribe(_ => TextOutput.Text = (Convert.ToInt32(TextOutput.Text) + 1).ToString());
Кажется, он делает то, что я хочу, но я открыт для дальнейших предложений/улучшений.
Другие советы
Я наткнулся на этот ответ и подумал, что в нем нет смысла:
leftHold.Zip(rightHold, (a,b) => true)
.TakeUntil(leftRelease.Amb(rightRelease))
.Subscribe(_ => TextOutput.Text =
(Convert.ToInt32(TextOutput.Text) + 1).ToString());
Zip
объединяет события таким образом, чтобы потребовалось, чтобы я отпустил левую и правую кнопки, прежде чем удерживать их снова.Если бы я отпустил вправо и удержал его снова, это наблюдаемое не сработало бы снова.- Я также подумал бы, что события hold
запускаются только один раз, поэтому
не должно быть никакой необходимости в
TakeUntil
позвони. - Также я не вижу, как этот ответ будет повторный запуск - кажется, он получает только одно значение.
Вот альтернатива:
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);
Я знаю, что этому вопросу годичной давности, но я хотел бы знать, не пропустил ли я что-то или этот ответ работает.