Multithreading 如何在动画完成之前阻止对方法的访问
我有一个Silverlight应用程序。它有一个基本的动画,其中一个矩形被动画设置到一个新的位置。该动画由两个双动画组成-一个变换X,另一个变换Y。效果正常 我基本上想阻止对这个动画方法的任何其他调用,直到前两个动画完成。我看到DoubleAnimation类有一个它触发的已完成事件,但我没有成功地构造任何类型的代码,直到这两个类都完成了才能成功地阻止它们 我尝试使用Monitor.Enter在输入方法时启用私有成员,然后从其中一个动画完成事件中释放锁,但我尝试链接这两个事件,以便在两个事件都完成之前不会释放锁,但都没有成功 以下是动画方法的外观:Multithreading 如何在动画完成之前阻止对方法的访问,multithreading,silverlight,Multithreading,Silverlight,我有一个Silverlight应用程序。它有一个基本的动画,其中一个矩形被动画设置到一个新的位置。该动画由两个双动画组成-一个变换X,另一个变换Y。效果正常 我基本上想阻止对这个动画方法的任何其他调用,直到前两个动画完成。我看到DoubleAnimation类有一个它触发的已完成事件,但我没有成功地构造任何类型的代码,直到这两个类都完成了才能成功地阻止它们 我尝试使用Monitor.Enter在输入方法时启用私有成员,然后从其中一个动画完成事件中释放锁,但我尝试链接这两个事件,以便在两个事件都完
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
var xIsComplete = false;
Duration duration = new Duration(new TimeSpan(0, 0, 0, 1, 350));
var easing = new ElasticEase() { EasingMode = EasingMode.EaseOut, Oscillations = 1, Springiness = 4 };
var animateX = new DoubleAnimation();
var animateY = new DoubleAnimation();
animateX.EasingFunction = easing;
animateX.Duration = duration;
animateY.EasingFunction = easing;
animateY.Duration = duration;
var sb = new Storyboard();
sb.Duration = duration;
sb.Children.Add(animateX);
sb.Children.Add(animateY);
Storyboard.SetTarget(animateX, rect);
Storyboard.SetTargetProperty(animateX, new PropertyPath("(Canvas.Left)"));
Storyboard.SetTarget(animateY, rect);
Storyboard.SetTargetProperty(animateY, new PropertyPath("(Canvas.Top)"));
animateX.To = newX;
animateY.To = newY;
sb.Begin();
}
编辑添加的更多信息
我一开始遇到这个问题是因为我从另一个方法调用这个方法,因为它处理了它调用动画的项目。我注意到这些东西并没有达到我预期的效果。我传入的新X/Y坐标基于项目当前位置,因此,如果在完成之前多次调用它,那么它最终将位于错误的位置。作为测试,我添加了一个只运行一次动画的按钮。成功了。但是,如果我连续多次单击按钮,我会看到与以前相同的行为:项目最终位于错误的位置
是的,Silverlight动画似乎在主UI线程上运行。在我尝试的一个测试中,我添加了两个属性,用于标记两个动画是否都已完成。在AnimateRectange方法中,我在调用Thread.Sleep的while循环中检查了它们。这个循环从未完成,所以它肯定在同一个线程上
因此,我创建了一个队列来按顺序处理动画:
private void ProcessAnimationQueue()
{
var items = this.m_animationQueue.GetEnumerator();
while (items.MoveNext())
{
while (this.m_isXanimationInProgress || this.m_isYanimationInProgress)
{
System.Threading.Thread.Sleep(100);
}
var item = items.Current;
Dispatcher.BeginInvoke(() => this.AnimateRectangle(item.Rect.Rect, item.X, item.Y));
}
}
然后我调用我的初始例程,该例程对动画进行排队,并在新线程上调用此方法。我看到了相同的结果。据我所知,Silverlight中的所有动画都是在UI线程上进行的。我猜无论如何只有UI线程在调用这个动画函数,所以我不确定使用锁定是否会有帮助。你真的想阻止整个线程还是仅仅阻止另一个动画开始 我建议采取类似的措施:
private bool isAnimating = false;
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
if (isAnimating)
return;
// rest of animation code
sb.Completed += (sender, e) =>
{
isAnimating = false;
};
isAnimating = true;
sb.Begin();
}
只需跟踪您当前是否正在使用标志设置动画,如果需要,请提前返回。如果您不想丢失潜在的动画,您的另一个选择是保留某种类型的动画队列,您可以在每个动画完成后检查/启动该队列。据我所知,Silverlight中的所有动画都发生在UI线程上。我猜无论如何只有UI线程在调用这个动画函数,所以我不确定使用锁定是否会有帮助。你真的想阻止整个线程还是仅仅阻止另一个动画开始 我建议采取类似的措施:
private bool isAnimating = false;
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
if (isAnimating)
return;
// rest of animation code
sb.Completed += (sender, e) =>
{
isAnimating = false;
};
isAnimating = true;
sb.Begin();
}
只需跟踪您当前是否正在使用标志设置动画,如果需要,请提前返回。如果你不想丢失潜在的动画,你的另一个选择是为动画保留某种队列,你可以在每个动画完成后检查/启动这些队列。这个问题让我非常感兴趣。事实上,我将在我的下一篇博文中包含它 简单地说,为了确保我们讨论的是同一件事,基本上你不想阻止对AnimateRectangle的调用,你只想对调用进行排队,以便在任何未完成的调用完成其动画后,执行该排队调用。如果前一个通话尚未开始,您可能需要将多个通话排队 因此,我们需要两件事:- 将本质上是异步操作的一种方法。sb.Begin to Completed事件视为顺序操作,一个操作仅在前一个操作完成时开始。 当一个或多个操作尚未完成时,将附加操作排队的一种方法。 异步操作服务 项目1在Silverlight中以无数种不同的方式出现,这是因为有很多东西是异步的。我通过一个简单的异步运行程序解决了这个问题。将AsyncOperationService代码添加到项目中 异步操作队列 它的项目2真的引起了我的兴趣。这里的变化是,当一组现有操作正在进行时,需要添加另一组操作。对于一般情况下的解决方案,我们需要一种线程安全的方法来包含另一个操作 以下是AsyncOperationQueue的基本内容:- 我们需要保存AsyncOperationQueue的一个实例:- 最后,我们需要重新创建AnimateRectangle,将操作排入队列:-
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
myAnimationQueue.Enqueue(GetAnimateRectangleOp(rect, newX, newY)
}
这个问题真的引起了我极大的兴趣。事实上,我要把它包括在我的n中 下一篇博文 简单地说,为了确保我们讨论的是同一件事,基本上你不想阻止对AnimateRectangle的调用,你只想对调用进行排队,以便在任何未完成的调用完成其动画后,执行该排队调用。如果前一个通话尚未开始,您可能需要将多个通话排队 因此,我们需要两件事:- 将本质上是异步操作的一种方法。sb.Begin to Completed事件视为顺序操作,一个操作仅在前一个操作完成时开始。 当一个或多个操作尚未完成时,将附加操作排队的一种方法。 异步操作服务 项目1在Silverlight中以无数种不同的方式出现,这是因为有很多东西是异步的。我通过一个简单的异步运行程序解决了这个问题。将AsyncOperationService代码添加到项目中 异步操作队列 它的项目2真的引起了我的兴趣。这里的变化是,当一组现有操作正在进行时,需要添加另一组操作。对于一般情况下的解决方案,我们需要一种线程安全的方法来包含另一个操作 以下是AsyncOperationQueue的基本内容:- 我们需要保存AsyncOperationQueue的一个实例:- 最后,我们需要重新创建AnimateRectangle,将操作排入队列:-
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
myAnimationQueue.Enqueue(GetAnimateRectangleOp(rect, newX, newY)
}
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
myAnimationQueue.Enqueue(GetAnimateRectangleOp(rect, newX, newY)
}