UWP:ListViewItem指针悬停时显示内部Button(VisualStateManager实现)
问题描述
现有一个ListView,其列表项包含一个Visibility设为Collapsed的Button。需要实现:当指针悬停在包含该Button的ListViewItem上时,让Button变为可见。能否通过VisualStateManager实现?尝试了以下代码但未成功,是否可以仅用XAML无需C#实现?
<ListView x:Name="Items" Width="500" Height="700"> <ListView.ItemTemplate> <DataTemplate> <Border> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="Normal"/> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OkButtom" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="400"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="Some Text" Grid.Column="0"/> <Button x:Name="OkButtom" Visibility="Collapsed" Content="OK" Grid.Column="1"/> </Grid> </Border> </DataTemplate> </ListView.ItemTemplate> </ListView>
解决方案
原代码不生效的核心原因:你把VisualStateGroups放在了DataTemplate内的Border上,但PointerOver状态属于ListViewItem容器,而非DataTemplate里的元素。以下提供两种纯XAML实现方式:
方式一:修改ListViewItem模板,用VisualStateManager控制
直接在ListViewItem的模板中定义状态切换逻辑,当Item进入悬停状态时,控制内部Button显示:
<ListView x:Name="Items" Width="500" Height="700"> <ListView.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="400"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="Some Text" Grid.Column="0"/> <Button x:Name="OkButtom" Visibility="Collapsed" Content="OK" Grid.Column="1"/> </Grid> </DataTemplate> </ListView.ItemTemplate> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListViewItem"> <Border x:Name="Root" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="PointerOver"> <Storyboard> <!-- 显示Button --> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OkButtom" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> <!-- 保留ListViewItem默认悬停背景效果 --> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <!-- 保留默认点击状态样式 --> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <!-- 承载ItemTemplate内容 --> <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListView.ItemContainerStyle> </ListView>
方式二:绑定ListViewItem的IsPointerOver属性
这种方式更简洁,直接通过数据绑定控制Button可见性,无需修改Item模板:
<!-- 先在页面资源中添加布尔值转可见性转换器 --> <Page.Resources> <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> </Page.Resources> <ListView x:Name="Items" Width="500" Height="700"> <ListView.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="400"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="Some Text" Grid.Column="0"/> <Button x:Name="OkButtom" Content="OK" Grid.Column="1" Visibility="{Binding IsPointerOver, RelativeSource={RelativeSource AncestorType=ListViewItem}, Converter={StaticResource BooleanToVisibilityConverter}}"/> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView>
注:WPF默认自带BooleanToVisibilityConverter;UWP需手动实现或引用相关资源转换器。
内容的提问来源于stack exchange,提问作者Nazarii Krypiak
相关产品推荐
相关产品推荐

