我是 Reactive Extensions 的新手,这就是我想出的做弹出烤面包机通知的方法。当鼠标经过烤面包机时,不透明度恢复到 100%。否则,它会逐渐淡出。
该代码有效,但我并不完全确信我没有泄漏资源,尤其是在 mouseOut 订阅中。此外,我不确定这是否是实现此功能的最佳方式。
任何批评,提示将不胜感激。
private void rxPop()
{
Rectangle toaster = (Rectangle)this.FindName("toaster1");
Thickness newToasterPosition = new Thickness(
toaster.Margin.Left, toaster.Margin.Top,
toaster.Margin.Right, toaster.Margin.Bottom + toaster.Height);
/* Animations */
Storyboard slideInAnimation = slide(toaster,
newToasterPosition,
TimeSpan.FromMilliseconds(450));
Storyboard fadeInAnimation = animateOpacity(toaster, 1.0, TimeSpan.FromMilliseconds(150));
Storyboard fadeOutAnimation = animateOpacity(toaster, 0.0, TimeSpan.FromSeconds(3));
/* Events */
var mouseEnter = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>
(h => toaster.MouseEnter += h,
h => toaster.MouseEnter -= h);
var mouseOut = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>
(h => toaster.MouseLeave += h,
h => toaster.MouseLeave -= h);
var slideInCompleted = Observable.FromEventPattern<EventHandler, EventArgs>(
h => slideInAnimation.Completed += h,
h => slideInAnimation.Completed -= h);
var fadeOutCompleted = Observable.FromEventPattern<EventHandler, EventArgs>(
h => fadeOutAnimation.Completed += h,
h => fadeOutAnimation.Completed -= h);
// slideIn then fadeOut
slideInCompleted.Subscribe(e => fadeOutAnimation.Begin());
var mouseEnterSubscription = mouseEnter
.ObserveOnDispatcher()
.Do(a =>
{
fadeOutAnimation.Pause();
fadeInAnimation.Begin();
slideInAnimation.Pause();
mouseOut.Do(
b =>
{
fadeOutAnimation.Begin();
fadeInAnimation.Stop();
slideInAnimation.Resume();
}).Subscribe();
})
.Subscribe();
fadeOutCompleted.Subscribe((e) => mouseEnterSubscription.Dispose());
slideInAnimation.Begin();
}
理想情况下,我希望以下列方式表达这些事件:
slideIn then fadeOut
unless mouseEnter
then fadeIn , slideIn.Pause
until mouseLeave
then fadeOut.Begin and slideIn.Resume
在 RX 中最接近的方法是什么?
更新 #1 *更新 #2 *(清理订阅())
这是一个有点干净的尝试。
protected CompositeDisposable _disposables = new CompositeDisposable();
private void rxPop()
{
IDisposable mouseEnterSubscription = null;
/* Business logic: slideIn then fadeOut then remove from visual tree */
_disposables.Add(
slideInAnimation
.BeginUntilDone()
.Select(slideInCompletedEvent =>
fadeOutAnimation.BeginUntilDone())
.Switch()
.Subscribe(fadeOutAnimationCompletedEvent =>
{
mouseEnterSubscription.Dispose();
// remove from visual tree
(toaster.Parent as Panel).Children.Remove(toaster);
}));
/* Business logic: mouseEnter/mouseLeave should pause/restart animations */
mouseEnterSubscription = mouseEnter
.ObserveOnDispatcher()
.Do(mouseEnterEventArgs =>
{
fadeOutAnimation.Pause();
fadeInAnimation.Begin();
slideInAnimation.Pause();
})
.Select(e => mouseOut)
.Switch()
.Do(mouseLeaveEventArgs =>
{
fadeOutAnimation.Begin();
fadeInAnimation.Stop();
slideInAnimation.Resume();
})
.Subscribe();
}
public static class RxExtensions
{
public static IObservable<EventPattern<EventArgs>> BeginUntilDone(this Storyboard sb)
{
var tmp = Observable.FromEventPattern(
h => sb.Completed += h,
h => sb.Completed -= h);
sb.Begin();
return tmp;
}
}
我的问题是:
ObserveOnDispatcher() 是否正确完成?
Switch() 是否为我处理了以前的 IObservable?
我很难将以上内容翻译成 LINQ 查询语法
/* Business Logic */ var showToast = // Start by sliding in from slideInComplete in slideIn.BeginObservable() where slideInComplete // Then in parallel, fadeOut as well as wait for mouseEnter from fadeOutComplete in fadeOut.BeginObservable() from enter in mouseEnter // ... I'm lost here. // ... how do I express // ..... mouseEnter should pause fadeOut? select new Unit();