c# - Canvas 动画 - 不在循环中工作

标签 c# wpf xaml

您好,我无法理解我遇到的问题

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);
            }
        }
    }

现在有两种方法

1) 如果我删除循环,则每次单击按钮时 leftCounter 都会增加 1 并且 Canvas 将移动。向右比向左点击 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 会反射(reflect)更改。这就是为什么第一种方法可以一次又一次地工作。

您可以做的是启动工作线程并在那里进行修改,或者因为这似乎是类似动画的行为,所以使用计时器。

更新: 示例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线程。

关于c# - Canvas 动画 - 不在循环中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14964391/

相关文章:

c# - 在 VB NET 或 C# 中发布 PHP 数组

c# - WPF:绑定(bind)到 DataGrid 中行的 SelectedItem

c# - WPF:命名空间中不存在该名称

c# - 从 WPF 中删除额外的垂直空白

c# - WPF Visual Studio 设计器中的错误

xaml - Windows Phone 8.1 中没有省略号的文本修剪

c# - 正则表达式查找内部 if 条件

c# - Vlc.DotNet NextFrame

c# - 从 System.Collections.Generic.IEnumerable 中获取前 n 个元素

wpf - 无边框的 TabControl wpf (XP)