自定义样式WPF ToggleButton选中态移出鼠标后显示未选中颜色问题
自定义了带样式的WPF ToggleButton,设置了未选中、选中及鼠标悬停的不同颜色。点击后能正确显示选中状态颜色,但鼠标悬停在已选中的按钮上,移开鼠标后,按钮颜色变回未选中状态,尽管实际仍处于选中状态。
问题原因
CommonStates中的MouseOver状态会直接覆盖Border的背景色,鼠标离开回到Normal状态时,没有根据当前IsChecked值恢复对应颜色;- 自定义的
CheckedMouseOver状态不属于WPF默认的视觉状态组,无法被自动触发,导致选中状态下的悬停逻辑失效。
修复方案
修改视觉状态逻辑,确保CheckStates的状态在鼠标离开后能正确保留,同时让状态组合自动生效。以下是修复后的完整样式代码:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style TargetType="ToggleButton" x:Key="ToggleButtonTheme"> <Setter Property="Foreground" Value="Black"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ToggleButton"> <Grid> <Grid.Resources> <Storyboard x:Key="ToggleOnAnimation"> <DoubleAnimation Storyboard.TargetName="SlideButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" To="12" Duration="0:0:0.1"/> </Storyboard> <Storyboard x:Key="ToggleOffAnimation"> <DoubleAnimation Storyboard.TargetName="SlideButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" To="-12" Duration="0:0:0.1"/> </Storyboard> </Grid.Resources> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="Disabled"/> <VisualState x:Name="MouseOver"> <Storyboard> <ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#848383" Duration="0:0:0.1"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="CheckStates"> <VisualStateGroup.Transitions> <VisualTransition From="*" To="Checked" GeneratedDuration="0:0:0.2"/> <VisualTransition From="*" To="Unchecked" GeneratedDuration="0:0:0.2"/> </VisualStateGroup.Transitions> <VisualState x:Name="Unchecked"> <Storyboard> <DoubleAnimation Storyboard.TargetName="SlideButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" To="-12" Duration="0:0:0.1"/> <ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#a3a2a2" Duration="0:0:0.2"/> </Storyboard> </VisualState> <VisualState x:Name="Checked"> <Storyboard> <DoubleAnimation Storyboard.TargetName="SlideButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" To="12" Duration="0:0:0.1"/> <ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#474646" Duration="0:0:0.2" FillBehavior="HoldEnd"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="Border" Background="#a3a2a2" CornerRadius="12" BorderThickness="0"> <Grid> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5"/> <Border x:Name="SlideButton" Background="White" CornerRadius="13" BorderThickness="0" Width="16" Height="16"> <Border.RenderTransform> <TranslateTransform X="0"/> </Border.RenderTransform> </Border> </Grid> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
关键修改点
- 给
Checked状态的ColorAnimation添加FillBehavior="HoldEnd",确保动画结束后保持目标颜色,不会因为回到Normal状态而重置; - 添加
VisualStateGroup.Transitions,保证状态切换时的动画平滑执行,避免状态冲突; - 移除无效的
CheckedMouseOver状态,WPF会自动组合CommonStates和CheckStates的状态:当按钮处于Checked+MouseOver时,悬停颜色会覆盖选中颜色;鼠标离开后回到Checked+Normal,选中状态的颜色会被正确保留。
内容的提问来源于stack exchange,提问作者Biswind
相关产品推荐
相关产品推荐

