如何在XAML中实现GIF无限循环播放?
问题描述
在XAML和PowerShell开发中,使用MediaElement播放GIF时遇到循环故障:GIF仅播放一次就停滞。尝试过停止后设置Position = [TimeSpan]::Zero再播放、直接重新设置源等方法均无效;仅将源设为$null再重新赋值能实现循环,但会产生严重闪烁。
当前代码如下:
PowerShell代码
function Get-Controls { # Find and assign various UI controls from the loaded XAML window by their names $global:Load_Installing_lbl = $global:window.FindName("Installing_lbl") $global:Load_Loader_gpl = $global:window.FindName("Loader_gpl") $global:LoaderNum = 1 $Load_Loader_gpl.Source = [Uri]::new("$PSScriptRoot\Loaders\Loader ($global:LoaderNum).gif") $global:Load_Loader_gpl.Add_MouseLeftButtonDown({ $global:LoaderNum++ if (-not (Test-Path "$PSScriptRoot\Loaders\Loader ($global:LoaderNum).gif")) { $global:LoaderNum = 1 } # Reset the loader to ensure the new GIF will play infinitely $Load_Loader_gpl.Stop() $Load_Loader_gpl.Source = [Uri]::new("$PSScriptRoot\Loaders\Loader ($global:LoaderNum).gif") $Load_Loader_gpl.Play() }) $Load_Loader_gpl.add_MediaEnded({ $wert = [Environment]::GetEnvironmentVariable("Installation", "User") if ($wert -eq "FINISH") { [Environment]::SetEnvironmentVariable("Installation", $null, "User") $global:Window.Close() } else { # Temporarily set the source to null to reset the GIF $Load_Loader_gpl.Stop() $Load_Loader_gpl.Position = [TimeSpan]::Zero # Set the initial position to zero Write-Host "t0.20" $Load_Loader_gpl.Play() } }) # Ensure the GIF plays in an endless loop initially $Load_Loader_gpl.Position = [TimeSpan]::Zero # Set the initial position to zero $Load_Loader_gpl.Play() }
XAML代码
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="MainWindow" Height="300" Width="300" WindowStyle="None" AllowsTransparency="True" Background="Transparent"> <Border CornerRadius="0, 20, 0, 20" Background="LightGray" BorderBrush="#FFFDC400" BorderThickness="5"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Label Name="Installing_lbl" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="24">Installing Test....</Label> <MediaElement Width="200" Height="200" Grid.Row="1" Margin="10" Name="Loader_gpl" LoadedBehavior="Manual" UnloadedBehavior="Stop"> </MediaElement> </Grid> </Border> </Window>
解决方案:用
Image控件替代MediaElement实现无闪烁循环 MediaElement本身对GIF的循环播放支持有限,容易出现重置失效或闪烁问题。改用Image控件配合BitmapImage的动画特性,能更稳定地实现无闪烁无限循环。
修改后的XAML代码
将原有的MediaElement替换为Image控件:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="MainWindow" Height="300" Width="300" WindowStyle="None" AllowsTransparency="True" Background="Transparent"> <Border CornerRadius="0, 20, 0, 20" Background="LightGray" BorderBrush="#FFFDC400" BorderThickness="5"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Label Name="Installing_lbl" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="24">Installing Test....</Label> <!-- 替换MediaElement为Image控件 --> <Image Width="200" Height="200" Grid.Row="1" Margin="10" Name="Loader_img" Stretch="Uniform"> </Image> </Grid> </Border> </Window>
修改后的PowerShell代码
通过BitmapImage加载GIF,并利用其内置的动画循环特性,无需手动处理MediaEnded事件:
function Get-Controls { $global:Load_Installing_lbl = $global:window.FindName("Installing_lbl") $global:Load_Loader_img = $global:window.FindName("Loader_img") $global:LoaderNum = 1 # 定义加载GIF的函数 function Load-Gif { param([string]$Path) $bitmap = New-Object System.Windows.Media.Imaging.BitmapImage $bitmap.BeginInit() $bitmap.UriSource = [Uri]::new($Path) $bitmap.CacheOption = [System.Windows.Media.Imaging.BitmapCacheOption]::OnLoad $bitmap.EndInit() # 确保GIF动画循环播放 $bitmap.DecodePixelWidth = 200 # 匹配Image控件宽度,避免拉伸失真 $Load_Loader_img.Source = $bitmap } # 初始加载GIF Load-Gif -Path "$PSScriptRoot\Loaders\Loader ($global:LoaderNum).gif" # 点击切换GIF $global:Load_Loader_img.Add_MouseLeftButtonDown({ $global:LoaderNum++ $gifPath = "$PSScriptRoot\Loaders\Loader ($global:LoaderNum).gif" if (-not (Test-Path $gifPath)) { $global:LoaderNum = 1 $gifPath = "$PSScriptRoot\Loaders\Loader ($global:LoaderNum).gif" } Load-Gif -Path $gifPath }) # 监听安装完成信号 $timer = New-Object System.Windows.Threading.DispatcherTimer $timer.Interval = [TimeSpan]::FromMilliseconds(500) $timer.Add_Tick({ $wert = [Environment]::GetEnvironmentVariable("Installation", "User") if ($wert -eq "FINISH") { [Environment]::SetEnvironmentVariable("Installation", $null, "User") $timer.Stop() $global:Window.Close() } }) $timer.Start() }
方案优势
- 无闪烁:
BitmapImage加载GIF时会缓存帧,切换或循环时不会出现源重置导致的闪烁 - 无需手动循环:GIF的动画循环由WPF内置处理,无需监听
MediaEnded事件手动重置 - 更稳定:避免了
MediaElement对GIF支持的兼容性问题
备选方案:修复
MediaElement的循环逻辑 如果必须使用MediaElement,可以尝试在MediaEnded事件中通过Dispatcher异步重置位置,确保操作在UI线程执行:
$Load_Loader_gpl.add_MediaEnded({ $wert = [Environment]::GetEnvironmentVariable("Installation", "User") if ($wert -eq "FINISH") { [Environment]::SetEnvironmentVariable("Installation", $null, "User") $global:Window.Close() } else { # 使用Dispatcher异步执行重置,确保在UI线程操作 $Load_Loader_gpl.Dispatcher.InvokeAsync({ $Load_Loader_gpl.Stop() $Load_Loader_gpl.Seek([TimeSpan]::Zero, [System.Windows.Media.MediaSeekMode]::FrameNearest) $Load_Loader_gpl.Play() }) } })
注意:此方案仍可能存在部分GIF循环失效的情况,不如Image控件方案稳定。
内容的提问来源于stack exchange,提问作者MAB
相关产品推荐
相关产品推荐

