WPF如何基于自定义事件触发属性动画?
解决方案:用定时器触发Border背景色动画
WPF中定时器的Elapsed事件属于后台线程触发,不需要在XAML中关联该事件,直接在后台代码中绑定事件处理逻辑即可,核心是要通过Dispatcher切换到UI线程操作控件。以下是具体实现步骤:
1. XAML部分(保留动画定义或直接后台创建)
如果想复用原有动画逻辑,可在XAML中定义Storyboard:
<Window x:Class="WpfColorTimer.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="450" Width="800"> <Grid> <!-- 要动画的Border,设置Name方便后台调用 --> <Border x:Name="TargetBorder" Width="200" Height="200" Background="LightBlue"> <Border.Resources> <!-- 定义背景色切换动画 --> <Storyboard x:Key="BgColorStoryboard"> <ColorAnimation Storyboard.TargetName="TargetBorder" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" From="LightBlue" To="LightGreen" Duration="0:0:0.5" AutoReverse="True" RepeatBehavior="1x"/> </Storyboard> </Border.Resources> </Border> </Grid> </Window>
2. 后台C#代码(定时器绑定与UI线程调度)
在窗口后台代码中初始化定时器,绑定Elapsed事件,并通过Dispatcher.Invoke确保UI操作在主线程执行:
using System; using System.Timers; using System.Windows; using System.Windows.Media.Animation; namespace WpfColorTimer { public partial class MainWindow : Window { private Timer _bgTimer; public MainWindow() { InitializeComponent(); SetupTimer(); } private void SetupTimer() { // 初始化1秒间隔的定时器 _bgTimer = new Timer(1000); _bgTimer.Elapsed += OnBgTimerElapsed; _bgTimer.Start(); } private void OnBgTimerElapsed(object sender, ElapsedEventArgs e) { // 定时器在后台线程,必须通过Dispatcher切换到UI线程 Dispatcher.Invoke(() => { // 调用XAML中定义的Storyboard var storyboard = (Storyboard)TargetBorder.Resources["BgColorStoryboard"]; storyboard.Begin(); }); } // 窗口关闭时释放定时器,避免内存泄漏 protected override void OnClosed(EventArgs e) { base.OnClosed(e); _bgTimer?.Stop(); _bgTimer?.Dispose(); } } }
简化方案:直接后台创建动画
如果不需要复用XAML中的动画,也可以直接在后台代码创建动画并应用:
private void OnBgTimerElapsed(object sender, ElapsedEventArgs e) { Dispatcher.Invoke(() => { var colorAnim = new ColorAnimation { From = Colors.LightBlue, To = Colors.LightGreen, Duration = TimeSpan.FromSeconds(0.5), AutoReverse = true }; // 直接将动画应用到Border的背景色属性 ((SolidColorBrush)TargetBorder.Background).BeginAnimation(SolidColorBrush.ColorProperty, colorAnim); }); }
关键注意点
- 定时器的
Elapsed事件运行在非UI线程,必须使用Dispatcher.Invoke/Dispatcher.BeginInvoke切换到UI线程,否则会触发跨线程操作UI的异常。 - 窗口关闭时务必停止并释放定时器,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Curtwagner1984
相关产品推荐
相关产品推荐

