如何通过Style的IsSelected触发器调用VisualStateManager.GoToState?
实现方法说明
WPF原生的Style Trigger无法直接调用VisualStateManager.GoToState,因为它仅支持设置属性、启动Storyboard等有限操作。要实现你要的效果,有两种常用方案:
方案一:使用Microsoft.Xaml.Behaviors.Wpf内置行为
这是最便捷的方式,需要先安装NuGet包Microsoft.Xaml.Behaviors.Wpf。
- 在XAML中添加行为命名空间:
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
- 在ListBoxItem的ControlTemplate里添加属性变化触发器,绑定
IsSelected属性触发状态切换:
<Style TargetType="ListBoxItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <Grid x:Name="rootGrid"> <!-- 你的VisualStateGroups定义 --> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="PopupStates"> <VisualState x:Name="PopupClosed"> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ContextPopup" Storyboard.TargetProperty="IsOpen"> <DiscreteBooleanKeyFrame KeyTime="0:0:0.25" Value="False" /> </BooleanAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="rootGrid" Storyboard.TargetProperty="(Panel.Background)"> <DiscreteObjectKeyFrame KeyTime="0:0:0.25" Value="{DynamicResource BrushIconComboBox_Popup_Closed_Background}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="PopupOpen"> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ContextPopup" Storyboard.TargetProperty="IsOpen"> <DiscreteBooleanKeyFrame KeyTime="0:0:0.25" Value="True" /> </BooleanAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="rootGrid" Storyboard.TargetProperty="(Panel.Background)"> <DiscreteObjectKeyFrame KeyTime="0:0:0.25" Value="{DynamicResource BrushIconComboBox_Popup_Open_Background}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <!-- 交互触发器:监听IsSelected变为True时切换状态 --> <i:Interaction.Triggers> <i:PropertyChangedTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True"> <i:GoToStateAction StateName="PopupClosed" /> </i:PropertyChangedTrigger> </i:Interaction.Triggers> <!-- 你的Popup控件 --> <Popup x:Name="ContextPopup" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
方案二:自定义TriggerAction(无需第三方库)
如果不想引入第三方库,可以自己实现一个触发动作类:
- 编写自定义Action类:
using System.Windows; using System.Windows.Interactivity; public class GoToStateAction : TriggerAction<FrameworkElement> { public static readonly DependencyProperty StateNameProperty = DependencyProperty.Register(nameof(StateName), typeof(string), typeof(GoToStateAction)); public string StateName { get => (string)GetValue(StateNameProperty); set => SetValue(StateNameProperty, value); } protected override void Invoke(object parameter) { if (AssociatedObject != null && !string.IsNullOrEmpty(StateName)) { VisualStateManager.GoToState(AssociatedObject, StateName, true); } } }
- 在XAML中引用这个类,并在Style的Trigger里使用:
<!-- 先添加自定义类的命名空间,假设类在local命名空间下 --> xmlns:local="clr-namespace:YourNamespace" <Style TargetType="ListBoxItem"> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Trigger.EnterActions> <local:GoToStateAction StateName="PopupClosed" /> </Trigger.EnterActions> </Trigger> </Style.Triggers> <!-- 你的ControlTemplate和VisualStateGroups定义 --> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <!-- 模板内容 --> </ControlTemplate> </Setter.Value> </Setter> </Style>
内容的提问来源于stack exchange,提问作者cpdev
相关产品推荐
相关产品推荐

