纯XAML实现Border悬停时切换Image源的技术问询
问题描述
我有一个包含Border的UserControl,Border内的StackPanel里有Image和TextBlock元素。想在纯XAML中实现当Border被鼠标悬停时切换Image的Source。目前能轻松修改Border的背景,也能在Image自身悬停时切换源,但希望触发条件是Border的悬停状态。
现有样式代码:
<Style TargetType="TextBlock" x:Key="Button.Text"> <Setter Property="FontFamily" Value="{StaticResource Fonts.InterMedium}"/> <Setter Property="FontSize" Value="10"/> <Setter Property="Foreground" Value="Gray"/> </Style> <Style TargetType="Border" x:Key="Button.Border"> <Setter Property="Background" Value="Gray" /> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="Blue" /> </Trigger> </Style.Triggers> </Style>
现有Border代码:
<Border CornerRadius="6" Width="80" HorizontalAlignment="Left" Style="{StaticResource Button.Border}" > <StackPanel> <behavior:Interaction.Triggers> <behavior:EventTrigger EventName="MouseLeftButtonDown"> <behavior:InvokeCommandAction Command="{Binding DataContext.RestoreCommand, RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}}" /> </behavior:EventTrigger> </behavior:Interaction.Triggers> <Image Margin="0, 8, 0, 0" HorizontalAlignment="Center" Width="24" Height="24" > <Image.Style> <Style TargetType="Image"> <Setter Property="Source" Value="component/Resources/Icon.ReverseLeft.png"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Source" Value="component/Resources/Icon.ReverseLeft.Hover.png"/> </Trigger> </Style.Triggers> </Style> </Image.Style> </Image> <TextBlock Style="{StaticResource Button.Text}" Margin="0, 2, 0, 4" HorizontalAlignment="Center" Text="{DynamicResource Restore}" /> </StackPanel> </Border>
解决方案
方法一:在Image的Style中绑定Border的悬停状态
修改Image的Style,将原有的Trigger替换为DataTrigger,通过RelativeSource获取父级Border的IsMouseOver属性作为触发条件:
<Image Margin="0, 8, 0, 0" HorizontalAlignment="Center" Width="24" Height="24"> <Image.Style> <Style TargetType="Image"> <Setter Property="Source" Value="component/Resources/Icon.ReverseLeft.png"/> <Style.Triggers> <DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=Border}}" Value="True"> <Setter Property="Source" Value="component/Resources/Icon.ReverseLeft.Hover.png"/> </DataTrigger> </Style.Triggers> </Style> </Image.Style> </Image>
方法二:将状态逻辑整合到Border的Style中
如果希望把相关状态统一管理在Border的Style里,可给Image命名后,在Border的Trigger中直接修改其Source:
1. 给Image添加命名
<Image x:Name="ControlIcon" Margin="0, 8, 0, 0" HorizontalAlignment="Center" Width="24" Height="24" Source="component/Resources/Icon.ReverseLeft.png"/>
2. 修改Border的Style
<Style TargetType="Border" x:Key="Button.Border"> <Setter Property="Background" Value="Gray" /> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="Blue" /> <Setter TargetName="ControlIcon" Property="Source" Value="component/Resources/Icon.ReverseLeft.Hover.png"/> </Trigger> <Trigger Property="IsMouseOver" Value="False"> <Setter TargetName="ControlIcon" Property="Source" Value="component/Resources/Icon.ReverseLeft.png"/> </Trigger> </Style.Triggers> </Style>
注意:这种方式要求Image是Border的直接/间接子元素,且Border与Image处于同一命名空间下。若Border的Style是全局资源,建议重构Border的Template,将Image包含在内以确保TargetName能正确识别。
方法三:使用VisualStateManager(适合多状态管理)
如果需要同时管理多种状态(如按下、禁用等),可使用VisualStateManager实现:
<Border CornerRadius="6" Width="80" HorizontalAlignment="Left" Style="{StaticResource Button.Border}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ControlIcon" Storyboard.TargetProperty="Source"> <DiscreteObjectKeyFrame KeyTime="0" Value="component/Resources/Icon.ReverseLeft.Hover.png"/> </ObjectAnimationUsingKeyFrames> <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Blue" Duration="0"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <StackPanel> <behavior:Interaction.Triggers> <behavior:EventTrigger EventName="MouseLeftButtonDown"> <behavior:InvokeCommandAction Command="{Binding DataContext.RestoreCommand, RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}}"/> </behavior:EventTrigger> </behavior:Interaction.Triggers> <Image x:Name="ControlIcon" Margin="0, 8, 0, 0" HorizontalAlignment="Center" Width="24" Height="24" Source="component/Resources/Icon.ReverseLeft.png"/> <TextBlock Style="{StaticResource Button.Text}" Margin="0, 2, 0, 4" HorizontalAlignment="Center" Text="{DynamicResource Restore}"/> </StackPanel> </Border>
内容的提问来源于stack exchange,提问作者zzDiego
相关产品推荐
相关产品推荐

