WPF中实现Rectangle.Fill的ImageSource切换淡入淡出动画
实现图片切换时的淡入淡出动画方案
这里提供两种实用的WPF实现思路,基于你现有代码改造即可:
方案一:双Image叠加+绑定更新触发动画
核心思路是通过两个重叠的Image控件,切换它们的透明度实现淡入淡出效果,用绑定更新事件触发动画。
修改后的XAML代码:
<Rectangle RadiusX="1" RadiusY="1" Width="20" Height="20" Stroke="Black" StrokeThickness="0.1" Stretch="Uniform"> <Rectangle.Fill> <VisualBrush> <VisualBrush.Visual> <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=Rectangle}, Path=Width}" Height="{Binding RelativeSource={RelativeSource AncestorType=Rectangle}, Path=Height}"> <!-- 显示旧图片的容器 --> <Image x:Name="OldImage" Stretch="Uniform" Opacity="1"> <Image.Source> <Binding Path="ImageSource" Mode="OneWay" NotifyOnTargetUpdated="True"/> </Image.Source> </Image> <!-- 显示新图片的容器,初始透明 --> <Image x:Name="NewImage" Stretch="Uniform" Opacity="0"> <Image.Source> <Binding Path="ImageSource" Mode="OneWay" NotifyOnTargetUpdated="True"/> </Image.Source> </Image> </Grid> </VisualBrush.Visual> </VisualBrush> </Rectangle.Fill> <Rectangle.Triggers> <!-- 绑定目标更新时触发动画 --> <EventTrigger RoutedEvent="Binding.TargetUpdated"> <BeginStoryboard> <Storyboard> <!-- 旧图片淡出 --> <DoubleAnimation Storyboard.TargetName="OldImage" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.3"/> <!-- 新图片淡入 --> <DoubleAnimation Storyboard.TargetName="NewImage" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.3"/> <!-- 动画结束后同步旧图片源,避免重复加载 --> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OldImage" Storyboard.TargetProperty="Source"> <DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{Binding ImageSource}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Rectangle.Triggers> </Rectangle>
关键注意点:绑定必须添加NotifyOnTargetUpdated="True",否则无法触发动画事件。
方案二:VisualStateManager状态切换
通过ViewModel新增状态属性,配合VisualState管理淡入淡出逻辑,结构更清晰。
1. ViewModel新增状态属性(需实现INotifyPropertyChanged)
private ImageSource _imageSource; public ImageSource ImageSource { get => _imageSource; set { IsImageChanging = true; // 延迟设置新图片,给淡出动画留执行时间 Task.Delay(300).ContinueWith(_ => { _imageSource = value; OnPropertyChanged(nameof(ImageSource)); IsImageChanging = false; }, TaskScheduler.FromCurrentSynchronizationContext()); } } private bool _isImageChanging; public bool IsImageChanging { get => _isImageChanging; set { _isImageChanging = value; OnPropertyChanged(nameof(IsImageChanging)); } }
2. 修改View的XAML代码
<Rectangle RadiusX="1" RadiusY="1" Width="20" Height="20" Stroke="Black" StrokeThickness="0.1" Stretch="Uniform"> <VisualStateManager.VisualStateGroups> <VisualStateGroup Name="ImageStates"> <VisualState Name="Normal"> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3"/> </Storyboard> </VisualState> <VisualState Name="Changing"> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Rectangle.Style> <Style TargetType="Rectangle"> <Setter Property="Fill"> <Setter.Value> <ImageBrush ImageSource="{Binding ImageSource}"/> </Setter.Value> </Setter> <Style.Triggers> <DataTrigger Binding="{Binding IsImageChanging}" Value="True"> <Setter Property="VisualStateManager.VisualStateName" Value="Changing"/> </DataTrigger> <DataTrigger Binding="{Binding IsImageChanging}" Value="False"> <Setter Property="VisualStateManager.VisualStateName" Value="Normal"/> </DataTrigger> </Style.Triggers> </Style> </Rectangle.Style> </Rectangle>
通用注意事项
- 动画时长(
Duration="0:0:0.3")可根据需求调整,单位是时:分:秒。 - 必须确保ViewModel的所有绑定属性正确实现
INotifyPropertyChanged接口,否则绑定和动画触发都会失效。
内容的提问来源于stack exchange,提问作者AndyS
相关产品推荐
相关产品推荐

