WPF 基于帧的动画

WPF 动画 插值动画、关键帧动画、路径动画 需要注意,BeginAnimation()方法由IAnimatable接口定义(只要实现了该接 口,都会有这个方法),但只有元素调用这个方法才能应用动画。如果是Animation类的实例调用该方法,没有意义,因为没有指定动画应用于哪个对象。在某一个时候,显示“raymond”,然后在下一个时候,显示“jack”。例如宽度属性,类型为double,可以设定动画为在1s的时间内,值从0变到10。1)定义:插值动画是指,属性值从某一个值,经过一段时间后,连续变化值另一个值的动画。因此只能填充“帧”。 阅读详情

 除基于属性的动画系统外,WPF提供了一种创建基于帧的动画的方法,这种方法只使用代码。需要做的全部工作是响应静态的CompositionTarge.Rendering事件,触发该事件是为了给每帧获取内容。这是一种非常低级的方法,除非使用标准的基于属性的动画模型不能满足需要(例如,构建简单的侧边滚动游戏、创建基于物理的动画式构建粒子效果模型(如火焰、雪花以及气泡)),否则不会希望使用这种方法。

  构建基于帧的动画的基本技术很容易。只需要为静态的CompositionTarget.Rendering事件关联事件处理程序。一旦关联事件处理程序,WPF就开始不断地调用这个事件处理程序(只要渲染代码的执行速度足够快,WPF每秒将调用60次)。在渲染事件处理程序中,需要在窗口中相应地创建或调整元素。换句话说,需要自行管理全部工作。当动画结束时,分离事件处理程序。

  下图显示了一个简单示例。在此,随机数量的圆从Canvas面板的顶部向底部下落。它们(根据随机生成的开始速度)以不同速度下降,但一相同的速率加速。当所有的圆到达底部时,动画结束。

 在这个示例中,每个下落的圆由Ellipse元素表示。使用自定义的EllipseInfo类保存椭圆的引用,并跟踪对于物理模型而言十分重要的一些细节。在这个示例中,只有如下信息很重要——椭圆沿X轴的移动速度(可很容易地扩张这个类,使其包含沿着Y轴运动的速度、额外的加速信息等)。

public class EllipseInfo
    {
        public Ellipse Ellipse
        {
            get;
            set;
        }

        public double VelocityY
        {
            get;
            set;
        }

        public EllipseInfo(Ellipse ellipse, double velocityY)
        {
            VelocityY = velocityY;
            Ellipse = ellipse;
        }
    }

 应用程序使用集合跟踪每个椭圆的EllipseInfo对象。还有几个窗口级别的字段,它们记录计算椭圆下落时使用的各种细节。可很容易地使这些细节变成可配置的。

private List<EllipseInfo> ellipses = new List<EllipseInfo>();

private double accelerationY = 0.1;
private int minStartingSpeed = 1;
private int maxStartingSpeed = 50;
private double speedRatio = 0.1;
private int minEllipses = 20;
private int maxEllipses = 100;
private int ellipseRadius = 10;

当单击其中某个按钮时,清空集合,并将事件处理程序关联到CompositionTarget.Rendering事件:

    private bool rendering = false;
        private void cmdStart_Clicked(object sender, RoutedEventArgs e)
        {
            if (!rendering)
            {
                ellipses.Clear();
                canvas.Children.Clear();

                CompositionTarget.Rendering += RenderFrame;
                rendering = true;
            }
        }
        private void cmdStop_Clicked(object sender, RoutedEventArgs e)
        {
            StopRendering();
        }

        private void StopRendering()
        {
            CompositionTarget.Rendering -= RenderFrame;
            rendering = false;
        }    

如果椭圆不存在,渲染代码会自动创建它们。渲染代码创建随机数量的椭圆(当前为20到100个),并使他们具有相同的尺寸和颜色。椭圆被放在Canvas面板的顶部,但他们沿着X轴随机移动:

private void RenderFrame(object sender, EventArgs e)
        {
            if (ellipses.Count == 0)
            {
                // Animation just started. Create the ellipses.
                int halfCanvasWidth = (int)canvas.ActualWidth / 2;

                Random rand = new Random();
                int ellipseCount = rand.Next(minEllipses, maxEllipses + 1);
                for (int i = 0; i < ellipseCount; i++)
                {
                    Ellipse ellipse = new Ellipse();
                    ellipse.Fill = Brushes.LimeGreen;
                    ellipse.Width = ellipseRadius;
                    ellipse.Height = ellipseRadius;
                    Canvas.SetLeft(ellipse, halfCanvasWidth + rand.Next(-halfCanvasWidth, halfCanvasWidth));
                    Canvas.SetTop(ellipse, 0);
                    canvas.Children.Add(ellipse);

                    EllipseInfo info = new EllipseInfo(ellipse, speedRatio * rand.Next(minStartingSpeed, maxStartingSpeed));
                    ellipses.Add(info);
                }
            }
        }    

 如果椭圆已经存在,代码处理更有趣的工作,以便进行动态显示。使用Canvas.SetTop()方法缓慢移动每个椭圆。移动距离取决于指定的速度。

 else
            {
                for (int i = ellipses.Count - 1; i >= 0; i--)
                {
                    EllipseInfo info = ellipses[i];
                    double top = Canvas.GetTop(info.Ellipse);
                    Canvas.SetTop(info.Ellipse, top + 1 * info.VelocityY);
            }

为提高性能,一旦椭圆到达Canvas面板的底部,就从跟踪集合中删除椭圆。这样,就不需要再处理它们。当遍历集合时,为了能够工作而不会导致丢失位置,需要向后迭代,从集合的末尾向起始位置迭代。

  如果椭圆尚未到达Canvas面板的底部,代码会提高速度(此外,为获得磁铁吸引效果,还可以根据椭圆与Canvas面板底部的距离来设置速度):

                    if (top >= (canvas.ActualHeight - ellipseRadius * 2 - 10))
                    {
                        // This circle has reached the bottom.
                        // Stop animating it.
                        ellipses.Remove(info);
                    }
                    else
                    {
                        // Increase the velocity.
                        info.VelocityY += accelerationY;
                    } 

最后,如果所有椭圆都已从集合中删除,就移除事件处理程序,然后结束动画:

                if (ellipses.Count == 0)
                    {
                        // End the animation.
                        // There's no reason to keep calling this method
                        // if it has no work to do.
                        StopRendering();
                    }        

示例完整XAML标记如下所示:

<Window x:Class="Animation.FrameBasedAnimation"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="FrameBasedAnimation" Height="396" Width="463.2">
    <Grid Margin="3">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <Button Margin="3" Padding="3" Click="cmdStart_Clicked">Start</Button>
            <Button Margin="3" Padding="3" Click="cmdStop_Clicked">Stop</Button>
        </StackPanel>
        <Canvas Name="canvas" Grid.Row="1" Margin="3"></Canvas>
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Animation
{
    /// <summary>
    /// FrameBasedAnimation.xaml 的交互逻辑
    /// </summary>
    public partial class FrameBasedAnimation : Window
    {
        public FrameBasedAnimation()
        {
            InitializeComponent();
        }

        private bool rendering = false;
        private void cmdStart_Clicked(object sender, RoutedEventArgs e)
        {
            if (!rendering)
            {
                ellipses.Clear();
                canvas.Children.Clear();

                CompositionTarget.Rendering += RenderFrame;
                rendering = true;
            }
        }
        private void cmdStop_Clicked(object sender, RoutedEventArgs e)
        {
            StopRendering();
        }

        private void StopRendering()
        {
            CompositionTarget.Rendering -= RenderFrame;
            rendering = false;
        }

        private List<EllipseInfo> ellipses = new List<EllipseInfo>();

        private double accelerationY = 0.1;
        private int minStartingSpeed = 1;
        private int maxStartingSpeed = 50;
        private double speedRatio = 0.1;
        private int minEllipses = 20;
        private int maxEllipses = 100;
        private int ellipseRadius = 10;

        private void RenderFrame(object sender, EventArgs e)
        {
            if (ellipses.Count == 0)
            {
                // Animation just started. Create the ellipses.
                int halfCanvasWidth = (int)canvas.ActualWidth / 2;

                Random rand = new Random();
                int ellipseCount = rand.Next(minEllipses, maxEllipses + 1);
                for (int i = 0; i < ellipseCount; i++)
                {
                    Ellipse ellipse = new Ellipse();
                    ellipse.Fill = Brushes.LimeGreen;
                    ellipse.Width = ellipseRadius;
                    ellipse.Height = ellipseRadius;
                    Canvas.SetLeft(ellipse, halfCanvasWidth + rand.Next(-halfCanvasWidth, halfCanvasWidth));
                    Canvas.SetTop(ellipse, 0);
                    canvas.Children.Add(ellipse);

                    EllipseInfo info = new EllipseInfo(ellipse, speedRatio * rand.Next(minStartingSpeed, maxStartingSpeed));
                    ellipses.Add(info);
                }
            }
            else
            {
                for (int i = ellipses.Count - 1; i >= 0; i--)
                {
                    EllipseInfo info = ellipses[i];
                    double top = Canvas.GetTop(info.Ellipse);
                    Canvas.SetTop(info.Ellipse, top + 1 * info.VelocityY);

                    if (top >= (canvas.ActualHeight - ellipseRadius * 2 - 10))
                    {
                        // This circle has reached the bottom.
                        // Stop animating it.
                        ellipses.Remove(info);
                    }
                    else
                    {
                        // Increase the velocity.
                        info.VelocityY += accelerationY;
                    }

                    if (ellipses.Count == 0)
                    {
                        // End the animation.
                        // There's no reason to keep calling this method
                        // if it has no work to do.
                        StopRendering();
                    }
                }
            }
        }
    }
    public class EllipseInfo
    {
        public Ellipse Ellipse
        {
            get;
            set;
        }

        public double VelocityY
        {
            get;
            set;
        }

        public EllipseInfo(Ellipse ellipse, double velocityY)
        {
            VelocityY = velocityY;
            Ellipse = ellipse;
        }
    }
}

显然,可扩展的这个动画以使圆跳跃和分散等。使用的技术是相同的——只需要使用更复杂的公式计算速度。

  当构建基于帧的动画时需要注意如下问题:它们不依赖与时间。换句话说,动画可能在性能好的计算机上运动更快,因为帧率会增加,会更频繁地调用CompositionTarget.Rendering事件。为补偿这种效果,需要编写考虑当前时间的代码。

  开始学习基于帧的动画的最好方式是查看WPF SDK提供的每一帧动画都非常详细的示例。该例演示了几种粒子系统效果,并且使用自定义的TimeTracker类实现了依赖与时间的基于帧的动画。

【愚公系列】2023年10月 WPF+上位机+工业互联 053-路径动画和自定义帧动画 WPF中的路径动画是一种通过将元素沿着路径移动来创建动画效果的技术。具体来说,就是将元素沿着定义好的路径对象进行动画运动,可以模拟物体在现实生活中沿着某个路径运动的效果。路径动画是一种非常抢眼的动画效果,在WPF应用程序中广泛应用。动画类名称:类型名称+ AnimationUsingPath下面介绍几种常用的路径动画类型:PathAnimationUsingPath:使用路径对象来控制动画。通过指定起点、终点和路径控制点的方式,可以定义出任意形状的路径动画效果。 阅读详情

相关推荐

2021-09-26 WPF上位机 46-路径动画和自定义帧动画

路径动画 根据Path数据,限定动画路径 动画类名称:类型名称+ AnimationUsingPath 三种类型: DoubleAnimationUsingPath MatrixAnimationUsingPath PointAnimationUsingPath 自定义帧动画 1、关键对象:CompositionTarget 动画时钟 <Window x:Class="Zhaoxi.AnimationStudy.Window7" xmlns="http://schemas.micro.

微软MVP Eleven 3万+

​WPF CompositionTarget.Rendering和 DispatcherTimer​

CompositionTarget.Rendering和 DispatcherTimer​ 运用

君子居易 1048

【朝夕教育】2023年09月 WPF+上位机+工业互联 053-路径动画和自定义帧动画

WPF中的路径动画是一种通过将元素沿着路径移动来创建动画效果的技术。具体来说,就是将元素沿着定义好的路径对象进行动画运动,可以模拟物体在现实生活中沿着某个路径运动的效果。路径动画是一种非常抢眼的动画效果,在WPF应用程序中广泛应用。动画类名称:类型名称+ AnimationUsingPath下面介绍几种常用的路径动画类型:PathAnimationUsingPath:使用路径对象来控制动画。通过指定起点、终点和路径控制点的方式,可以定义出任意形状的路径动画效果。

微软MVP Eleven 284

WPF渲染事件CompositionTarget.Rendering

CompositionTarget.Rendering Event WPF渲染之前出发该事件,参见 https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.media.compositiontarget.rendering?view=netframework-4.7.2

就在昨天之技术点滴 3980

WPF通过代码编写关键帧动画

WPF通过代码编写关键帧动画,实现了一组LED灯的颜色渐变。

手把手教你:在联想/戴尔笔记本上安装华为电脑管家,实现多屏协同(附详细避坑步骤)

本文详细指导如何在联想、戴尔等非华为笔记本上安装华为电脑管家,实现多屏协同功能。从硬件兼容性检查到定制化安装流程,再到功能调优与异常处理,提供了一套完整的解决方案,帮助用户突破品牌限制,享受华为生态的高效办公体验。

weixin_30251829的博客 804

WPF 使用CompositionTarget.Rendering实现平滑流畅滚动的ScrollViewer,支持滚轮、触控板、触摸屏和笔

为了解决以上问题,本文提出一种新的方案来实现平滑滚动ScrollViewer。该方案在和中直接处理(禁用)了系统的滚动效果,使用事件来驱动滚动动画。并针对滚轮方式和触控“跟手”分别进行优化,使用缓动滚动模型和精确滚动模型来实现平滑滚动。笔的支持得益于库提供的模拟,将笔输入映射为触摸输入。为了最直观和最简单地解决问题,我们将应用场景设置为垂直滚动,水平滚动可以通过类似的方式实现。

weixin_41383774的博客 184

解决 PyInstaller 与 `pathlib` 包不兼容的问题

为了避免 PyInstaller 和pathlib包的兼容性问题,最简单的解决办法就是卸载不必要的pathlib包。只需在命令行中运行卸载命令,然后重新打包即可。

Winfredzhang的博客 3216

WPF CompositionTarget

CompositionTarget 是一个类,表示其绘制你的应用程序的显示图面。 WPF 动画引擎提供了许多用于创建基于帧的动画的功能。 但是,有应用程序方案中,您需要通过基于每个帧来呈现控件。 CompositionTarget对象提供了创建基于每帧回调的自定义动画的功能。 每帧渲染之前触发CompositionTarget的Rendering事件。 用法: CompositionT...

weixin_34194551的博客 560

hi3519dv500 os04a10输入调试

因该sensor接在soc端的iic6,在驱动中(Hi3519DV500_SDK_V2.0.1.1\smp\a55_linux\source\mpp\cbb\isp\user\sensor\hi3519dv500\omnivision_os04a10\os04a10_sensor_ctl.c)注意总线的选择。mem_process_isolation=1 改为 mem_process_isolation=0。2、OT_MIPI_SET_HS_MODE配置为LANE_DIVIDE_MODE_1。

linus 3141

6.4 构网型储能的需求与配置

摘要: 构网型储能是新型电力系统的关键支撑技术,通过提供电压/频率形成、惯性和稳定控制能力,解决同步机退出导致的系统稳定性问题。其配置需遵循三大原则:1)容量配置以支撑需求为主导,兼顾能量服务;2)优先布局于电网薄弱点、稳定问题突出区域;3)采用自适应控制策略实现全工况优化。核心应用场景包括新能源送出通道稳定、负荷中心调频、黑启动电源等。规划方法需结合系统分析、量化指标和成本效益评估,实现技术经济最优。未来需重点关注构网/跟网混合系统的临界容量占比及自适应控制技术发展。

技术工作者 1132

WPF中的基于帧的动画:飘落的雪花

通过以上的步骤,你现在可以使用 WPF 创建一个简单的雪花下落动画了。当然,这只是冰山一角,你可以通过调整KeyTime和Value来改变雪花下落的速度和路径,甚至可以给每片雪花定义不同的动画,让它们看起来更加自然。

java专栏 1147

BraTS数据集保姆级使用指南:从下载、预处理到可视化(附Python脚本)

本文提供BraTS数据集的完整使用指南,涵盖从下载、预处理到可视化的全流程,并附有Python脚本示例。详细解析了医学影像处理中的数据结构、标准化流程和可视化技巧,帮助初学者快速掌握BraTS数据集的应用方法,提升医学影像分析效率。

weixin_27310417的博客 444

WPF使用SharpDX绘制帧动画

5.获取精灵图中图片数量,我这里的图片大小是 IconSize = new Size(34, 33)相关代码就介绍到这里了,未完善之处,后续会进行补充...

qq_31461977的博客 609

HQChart实战教程49-点击修改K线颜色及背景色

HQChart实战教程49-点击修改K线颜色及背景色需求效果图步骤1. 注册点击监听事件2. 修改K颜色添加一个自定义颜色的K线klineoption清空所有自定义颜色的K线option交流QQ群: 950092318HQChart代码地址完整例子 需求 对点击的K线修改颜色。 效果图 步骤 1. 注册点击监听事件 事件ID JSCHART_EVENT_ID.ON_CLICK_CHART_PAINT, 注册监听事件见教程 HQChart使用教程5- K线图控件操作函数说明 this.Create=func

小银 2903

ANFIS实现数据非线性回归附Matlab代码

在本文中,我们将介绍如何使用Matlab实现基于MSE的ANFIS非线性回归,并提供相应的源代码。ANFIS是一种融合了模糊逻辑和神经网络的方法,它可以通过学习数据集中的模式来构建一个模糊推理系统。ANFIS的训练过程基于最小化MSE,以提高模型的拟合能力。通过上述代码示例,我们可以使用基于MSE的ANFIS模型对数据进行非线性回归,并获得相应的预测结果。在示例中,我们定义了一个包含两个样本的新输入数据集 X_new,然后使用训练好的ANFIS模型进行预测,并将结果存储在变量 Y_pred 中。

2301_79326588的博客 469

WPF成长之路------帧动画(1)

原文:WPF成长之路------帧动画(1) 最近公司的一个项目因为是WPF的,而自己已经很长一段时间没有接触过WPF了,再加上之前没有做过wpf的动画效果,因此在学习的过程中也顺便记录一下,说不定以后还会用上,同时也算是总结一下吧!刚开始写博客,写得不好的地方大家多多见谅!不喜勿喷! 这个效果主要是通过各种图形的组合进行绘图,然后通过贝塞尔曲线绘制主...

weixin_33728708的博客 108

【AUTOSAR实战】:CAN发送邮箱忙导致报文发送丢帧的问题调试

本文档主要讨论了CAN总线通信中可能出现的TC377传输错误的分析和解决方案。文章提供了如何通过检查CAN传输和接收过程、识别传输缓冲区的类型和状态以及选择适当的内存保护功能来检测和解决此类错误的见解。经过多次尝试和分析,得出的结论是,修改CANIF缓冲的尺寸并重新分配报文给各个buffer并不能解决问题。此外,发送中断被抢占可能导致报文无法发送,最终也将此因素排除。本文档还提到了一些可能导致发送流程调度出现问题的因素,例如CANIF中报文引用Buffer不合理。

weixin_46481662的博客 3129

wpf 帧动画

帧动画实现很简单 <ImageBrush x:Key="speed_s" Stretch="Fill" ImageSource="/images/air/speed_s.png" /> <ImageBrush x:Key="speed_m" ImageSource="/images/air/speed_m.png" /> <I...

weixin_34351321的博客 231

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

WPF:Animation动画--KeyFramesExample帧动画(2)

KeyFrameAnimation每帧动画效果 实现效果: 方框滑块里内容与帧动画时滑块移动位置是相对的,即滑块前景边框在滑块静态背景内容中移动。。 实现帧间动画。 关注点:一、 滑块方框的背景画刷VisualBrush绑定到Image的几种方法实现? 1、源代码中作为背景方格DrawingBrush的资源实现:DrawingGro...

weixin_34087307的博客 239

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Wpf播放Gif的多帧动画

Wpf播放Gif的多帧动画 开发工具与关键技术:Visual Studio 作者:zhh 撰写时间:2020.8.8 最近想显示GIF动态表情,于是用了Image试了下,发现不行,只会显示第一帧。 所以看了下帮助文档,我用的是MediaElement 类,MediaElement 与图像类似,并且可以直接指定 Source URI。 在时钟模式中,MediaElement 可以看作是动画目标,因此它在计时树中具有相应的 Timeline 和 Clock 项。这种方式有一个局限就是图片路径必须是绝对路径 给

weixin_44540800的博客 571

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

小人快跑之WPF基础——图形与动画(一)

前言: 之前为了完成一些任务,因为公司只能限定一些网络访问且不能用存储设备进行拷贝,所以自己在家里写了一个demo就放到csdn的下载区回公司再下下来,令人意外的是这个非常小的demo居然两天里就有几十个下载还得到了几个评论(在我之前从来没有遇到过的)。想了一下干脆分享一下自己的学习心得好了。 接下来让我们初入WPF动画的世界吧 1.任务概述: 使用WPF模拟一个小人走路的动画效果。 之

yujunwu2525的专栏 6662

WPF:Animation动画--Per-FrameAnimation每帧动画效果(1)

Pre-FrameAnimation帧动画: ColorChangingExample颜色帧变化示例 实现效果:此方框实现每帧改变一次颜色 Rectangle.Fill填充纯色画刷SolidColorBrush, 后台代码实现CompositionTarget.Rendering事件,在每帧中更新纯色画刷的初始化的随机颜色。 pri...

weixin_34234829的博客 440
上一篇: WPF 基本动画
下一篇: WPF 透明
西飘客
博客等级 码龄12年 170粉丝 214原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值