画布动画-不在循环中工作
本文关键字:循环 工作 布动画 动画 | 更新日期: 2023-09-27 18:00:19
你好,我不能理解我有的问题
private void StartReplay(object sender, RoutedEventArgs e)
{
for (int i = 0; i <= 40; i++)
{
if (leftCounter < 20)
{
leftCounter++;
leftCounter2 = leftCounter;
Canvas.SetLeft(Kwadracik, leftCounter);
}
else
{
leftCounter2--;
Canvas.SetLeft(Kwadracik, leftCounter2);
}
}
}
现在2路
1) 如果我要删除循环,那么每次单击按钮时,leftCounter将增加1,画布将被移动。从右20比从左多点击多少我就点击多少。它按预期工作。先向右后向左
2) 当我用循环运行它时,当我点击按钮时,循环将继续。但它不会像我期望的那样起作用。我预计它会向右20,向左20(20+20=40)。但没有。它并没有向两个方面发展。它只是站着,因为它正在跳到最后。我看不到向右移动。即使我在每个循环步骤上都会有很小的延迟,GUI也会冻结,并且在循环结束后解冻,元素在所在的位置
为什么会有这种差异?我怎样才能跨过它?
此后面的XAML
<Canvas x:Name="canvas" HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle Name="Kwadracik" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Fill="Blue" />
</Canvas>
这是因为您可能正在从GUI线程调用StartReplay。只有在函数完成后,线程处理才会继续。换句话说,GUI在您的功能完成之前无法处理您的更改。当您在按钮点击处理程序(也是gui线程)中放置更改时,您将退出您的函数,之后gui将反映更改。这就是为什么第一种方法可以一点一点地工作。
您可以做的是启动工作线程并在那里进行修改,或者因为这似乎是类似动画的行为,所以使用Timers。
更新:示例1:
DispatcherTimer在调用线程中执行回调。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace CanvasAnimation
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer uiTimer;
double directionDelta = 1.0;
public MainWindow()
{
InitializeComponent();
uiTimer = new DispatcherTimer(); //This timer is created on GUI thread.
uiTimer.Tick += new EventHandler(uiTimerTick);
uiTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000/25); // 25 ticks per second
uiTimer.Start();
}
private void uiTimerTick(object sender, EventArgs e)
{
double currentLeft = Canvas.GetLeft(Kwadracik);
if (currentLeft < 0)
{
directionDelta = 1.0;
}
else if (currentLeft > 80)
{
directionDelta = -1.0;
}
currentLeft += directionDelta;
Canvas.SetLeft(Kwadracik, currentLeft);
}
}
}
示例2:使用简单计时器
using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
namespace CanvasAnimation
{
/// <summary>
/// Interaction logic for WorkerTimer.xaml
/// </summary>
public partial class WorkerTimer : Window
{
Timer timer;
double directionDelta = 1.0;
public WorkerTimer()
{
InitializeComponent();
timer = new Timer(this.timerTick, this, 0, 1000 / 25); // 25 fPS timer
}
protected void timerTick(Object stateInfo)
{
//This is not a GUI thread!!!!
//So we need to Invoke delegate with Dispatcher
this.Dispatcher.Invoke(new MoveCanvasDelegate(this.moveCanvas), null);
}
protected delegate void MoveCanvasDelegate();
protected void moveCanvas()
{
//This function must be called on GUI thread!!!
double currentLeft = Canvas.GetLeft(Kwadracik);
if (currentLeft < 0)
{
directionDelta = 1.0;
}
else if (currentLeft > 80)
{
directionDelta = -1.0;
}
currentLeft += directionDelta;
Canvas.SetLeft(Kwadracik, currentLeft);
}
}
}
同样的技术也适用于BackgroundWorker或其他非GUI线程。