【发布时间】:2011-11-24 20:17:35
【问题描述】:
我在网格中有一组按钮。对于这些按钮中的每一个,我想处理 MouseEnter 和 MouseLeave 事件来为按钮的高度设置动画(并做一些其他 有趣的 的事情)。这一切都很好,直到我开始将鼠标移动得太快并离开按钮,最终导致事件在另一个完成之前发生。确保事件在触发之前相互等待的最佳方法是什么?
更新:
按照 x0r 的建议,我将代码重构为一个内部类,该类继承自 Button,并具有执行动画所需的方法。不幸的是,这并没有真正解决问题,因为 - 我认为 - 我正在两个不同的地方处理第一个动画的 Completed 事件。 (如我错了请纠正我)。这是我的代码:
internal class MockButton : Button
{
#region Fields
private Storyboard _mouseEnterStoryBoard;
private Storyboard _mouseLeaveStoryBoard;
private Double _width;
#endregion
#region Properties
internal Int32 Index { get; private set; }
#endregion
#region Ctors
internal MockButton(Int32 index) : this(index, 200)
{
}
internal MockButton(Int32 index, Double width)
{
this.Index = index;
this._width = width;
}
#endregion
#region Event Handlers
internal void OnMouseEnter(Action action, Double targetAnimationHeight)
{
if (_mouseEnterStoryBoard == null)
{
_mouseEnterStoryBoard = new Storyboard();
DoubleAnimation heightAnimation = new DoubleAnimation();
heightAnimation.From = 10;
heightAnimation.To = targetAnimationHeight;
heightAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(300));
_mouseEnterStoryBoard.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("Height"));
Storyboard.SetTarget(heightAnimation, this);
_mouseEnterStoryBoard.Children.Add(heightAnimation);
}
_mouseEnterStoryBoard.Completed += (s, e) =>
{
action.Invoke();
};
_mouseEnterStoryBoard.Begin();
}
internal void OnMouseLeave()
{
if (_mouseLeaveStoryBoard == null)
{
_mouseLeaveStoryBoard = new Storyboard();
DoubleAnimation heightAnimation = new DoubleAnimation();
heightAnimation.To = 10;
heightAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(300));
_mouseLeaveStoryBoard.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("Height"));
Storyboard.SetTarget(heightAnimation, this);
_mouseLeaveStoryBoard.Children.Add(heightAnimation);
}
if (_mouseEnterStoryBoard.GetCurrentState() != ClockState.Stopped)
{
_mouseEnterStoryBoard.Completed += (s, e) =>
{
_mouseLeaveStoryBoard.Begin();
};
}
else
{
_mouseLeaveStoryBoard.Begin();
}
}
#endregion
}
更新 2:
某些事件会被多次触发。一个例子是我的Rule 对象的关闭按钮上的Click 事件...
public Rule(Action<Int32> closeAction)
{
this.Style = Application.Current.Resources["RuleDefaultStyle"] as Style;
this.CloseAction = closeAction;
this.Loaded += (s, e) =>
{
if (_closeButton != null)
{
_closeButton.Click += (btn, args) =>
{
if (this.CloseAction != null)
{
this.CloseAction.Invoke(this.Index);
}
};
if (_closeButtonShouldBeVisible)
{
_closeButton.Visibility = System.Windows.Visibility.Visible;
}
}
};
}
下面是Action<Int32> 我作为CloseAction 传递给Rule 对象:
private void RemoveRule(Int32 ruleIndex)
{
Rule ruleToRemove = Rules.FirstOrDefault(x => x.Index.Equals(ruleIndex));
Storyboard sb = new Storyboard();
DoubleAnimation animation = new DoubleAnimation();
sb.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("Opacity"));
animation.Duration = TimeSpan.FromMilliseconds(300);
animation.From = 1;
animation.To = 0;
sb.Children.Add(animation);
Storyboard.SetTarget(animation, ruleToRemove);
sb.Completed += (s, e) =>
{
if (Rules.FirstOrDefault(x => x.Index.Equals(ruleIndex)) != null)
{
this.Rules.RemoveAt(ruleIndex);
}
};
sb.Begin();
}
更新 3:
为了避免动画过早运行,我想我可以延迟MouseEnter 事件,所以如果用户滚动项目太快,它不会启动。但是我现在有一个问题:假设用户将鼠标悬停在该项目上,然后将鼠标移出。如果我使用 Storyboard.BeginTime 属性,那将无法防止这种行为发生,因为即使动画被延迟,它最终还是会开始......那么有什么方法可以防止这种情况发生吗?
有什么建议吗?
【问题讨论】:
标签: silverlight events animation silverlight-4.0 mouseevent