如何在 Windows UI 库中使用 ListViewItem 样式的 Reveal 悬停?
How do I use the Reveal hover in a ListViewItem style with the Windows UI Library?
我正在尝试为我们的 UWP 应用程序中的控件自定义默认的 ListViewItem 样式,但我无法使 Reveal hover/click 效果起作用。
在添加自定义样式之前,显示效果效果很好(使用默认的 ListView 控件)。我在设计视图中右键单击 ListView 控件,然后 select 编辑其他模板 -> 编辑生成的项目容器 (ItemContainerStyle) -> 编辑副本...此时样式 属性 设置为新生成的样式,但我还没有修改它,所以 UI 中应该没有任何改变。但是 Reveal hover/click 效果现在被破坏了。
我们的应用程序在其他地方使用 Windows UI 库 (Microsoft.UI.Xaml),因此 <XamlControlsResources />
已添加到 Application.Resources。如果我删除它,Reveal hover/click 效果会起作用。所以它似乎是定义自定义样式和添加破坏效果的 XamlControlsResources 的组合。我已经尝试将样式移动到 App.xaml 或一个单独的 ResourceDictionary 中,没有任何变化。我试过删除样式的各个部分以确定导致它损坏的原因。如果我删除模板的 Setter 它会起作用,但这正是我要自定义的。
根据 Microsoft Docs,"It's important to note that Reveal needs both the brush and the setters in it's Visual State to work correctly. Simply setting a control's brush to one of our Reveal brush resources alone won't enable Reveal for that control. Conversely, having only the targets or settings without the values being Reveal brushes will also not enable Reveal." 所以大概是 ListViewItemPresenter.RevealBackground 属性 或 VisualStateManager 导致它中断,但我不确定如何或为什么.
如何在不丢失悬停效果的情况下为我的 ListView 定义自定义样式(并且不删除 XamlControlsResources,因为我们的应用程序需要这样做)?
这是一个简单的重现:
App.xaml
<Application
x:Class="BrokenRevealEffect.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedTheme="Dark">
<Application.Resources>
<!-- Remove XamlControlsResources to see the Reveal hover/click effect. -->
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</Application.Resources>
</Application>
MainPage.xaml
<Page
x:Class="BrokenRevealEffect.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Page.Resources>
<!-- This is the default style for the ListViewItem. It has not been modified. -->
<Style x:Key="abc" TargetType="ListViewItem">
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Background" Value="{ThemeResource ListViewItemBackground}" />
<Setter Property="Foreground" Value="{ThemeResource ListViewItemForeground}" />
<Setter Property="TabNavigation" Value="Local" />
<Setter Property="IsHoldingEnabled" Value="True" />
<Setter Property="Padding" Value="12,0,12,0" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}" />
<Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}" />
<Setter Property="AllowDrop" Value="False" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter
x:Name="Root"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
CheckBrush="{ThemeResource ListViewItemCheckBrush}"
CheckMode="{ThemeResource ListViewItemCheckMode}"
ContentMargin="{TemplateBinding Padding}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Control.IsTemplateFocusTarget="True"
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
DragBackground="{ThemeResource ListViewItemDragBackground}"
DragForeground="{ThemeResource ListViewItemDragForeground}"
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
PressedBackground="{ThemeResource ListViewItemBackgroundPressed}"
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
RevealBackground="{ThemeResource ListViewItemRevealBackground}"
RevealBorderBrush="{ThemeResource ListViewItemRevealBorderBrush}"
RevealBorderThickness="{ThemeResource ListViewItemRevealBorderThemeThickness}"
SelectedBackground="{ThemeResource ListViewItemBackgroundSelected}"
SelectedForeground="{ThemeResource ListViewItemForegroundSelected}"
SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundSelectedPointerOver}"
SelectedPressedBackground="{ThemeResource ListViewItemBackgroundSelectedPressed}"
SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected" />
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverSelected">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverPressed">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PressedSelected">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="DisabledStates">
<VisualState x:Name="Enabled" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="Root.RevealBorderThickness" Value="0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ListViewItemPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid>
<!-- Remove ItemContainerStyle to see the Reveal hover/click effect. -->
<ListView ItemContainerStyle="{StaticResource abc}" ItemsSource="{x:Bind Items}" />
</Grid>
</Page>
MainPage.xaml.cs
using System.Collections.Generic;
using Windows.UI.Xaml.Controls;
namespace BrokenRevealEffect
{
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
}
public List<string> Items => new List<string> { "Red", "Yellow", "Blue", "Green" };
}
}
我发现可以通过使用自定义样式重复 RevealBackgroundBrush
SystemControlTransparentRevealBackgroundBrush
和 ListViewItemRevealBackground
的定义来解决此问题。
<RevealBackgroundBrush
x:Key="SystemControlTransparentRevealBackgroundBrush"
FallbackColor="Transparent"
TargetTheme="Light"
Color="Transparent" />
<StaticResource x:Key="ListViewItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
只需在 Page.Resources
或 App.Resources
或 ResourceDictionary
中的自定义 ListViewItem
样式之前添加此代码;无论您在哪里定义样式。
对于为什么这是必要的,我没有合乎逻辑的解释。这些资源已在 generic.xaml
中定义,因此这不是必需的,但它确实解决了问题。我会把这归因于 Windows UI 库中的错误。
我正在尝试为我们的 UWP 应用程序中的控件自定义默认的 ListViewItem 样式,但我无法使 Reveal hover/click 效果起作用。
在添加自定义样式之前,显示效果效果很好(使用默认的 ListView 控件)。我在设计视图中右键单击 ListView 控件,然后 select 编辑其他模板 -> 编辑生成的项目容器 (ItemContainerStyle) -> 编辑副本...此时样式 属性 设置为新生成的样式,但我还没有修改它,所以 UI 中应该没有任何改变。但是 Reveal hover/click 效果现在被破坏了。
我们的应用程序在其他地方使用 Windows UI 库 (Microsoft.UI.Xaml),因此 <XamlControlsResources />
已添加到 Application.Resources。如果我删除它,Reveal hover/click 效果会起作用。所以它似乎是定义自定义样式和添加破坏效果的 XamlControlsResources 的组合。我已经尝试将样式移动到 App.xaml 或一个单独的 ResourceDictionary 中,没有任何变化。我试过删除样式的各个部分以确定导致它损坏的原因。如果我删除模板的 Setter 它会起作用,但这正是我要自定义的。
根据 Microsoft Docs,"It's important to note that Reveal needs both the brush and the setters in it's Visual State to work correctly. Simply setting a control's brush to one of our Reveal brush resources alone won't enable Reveal for that control. Conversely, having only the targets or settings without the values being Reveal brushes will also not enable Reveal." 所以大概是 ListViewItemPresenter.RevealBackground 属性 或 VisualStateManager 导致它中断,但我不确定如何或为什么.
如何在不丢失悬停效果的情况下为我的 ListView 定义自定义样式(并且不删除 XamlControlsResources,因为我们的应用程序需要这样做)?
这是一个简单的重现:
App.xaml
<Application
x:Class="BrokenRevealEffect.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedTheme="Dark">
<Application.Resources>
<!-- Remove XamlControlsResources to see the Reveal hover/click effect. -->
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</Application.Resources>
</Application>
MainPage.xaml
<Page
x:Class="BrokenRevealEffect.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Page.Resources>
<!-- This is the default style for the ListViewItem. It has not been modified. -->
<Style x:Key="abc" TargetType="ListViewItem">
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Background" Value="{ThemeResource ListViewItemBackground}" />
<Setter Property="Foreground" Value="{ThemeResource ListViewItemForeground}" />
<Setter Property="TabNavigation" Value="Local" />
<Setter Property="IsHoldingEnabled" Value="True" />
<Setter Property="Padding" Value="12,0,12,0" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}" />
<Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}" />
<Setter Property="AllowDrop" Value="False" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter
x:Name="Root"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
CheckBrush="{ThemeResource ListViewItemCheckBrush}"
CheckMode="{ThemeResource ListViewItemCheckMode}"
ContentMargin="{TemplateBinding Padding}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Control.IsTemplateFocusTarget="True"
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
DragBackground="{ThemeResource ListViewItemDragBackground}"
DragForeground="{ThemeResource ListViewItemDragForeground}"
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
PressedBackground="{ThemeResource ListViewItemBackgroundPressed}"
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
RevealBackground="{ThemeResource ListViewItemRevealBackground}"
RevealBorderBrush="{ThemeResource ListViewItemRevealBorderBrush}"
RevealBorderThickness="{ThemeResource ListViewItemRevealBorderThemeThickness}"
SelectedBackground="{ThemeResource ListViewItemBackgroundSelected}"
SelectedForeground="{ThemeResource ListViewItemForegroundSelected}"
SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundSelectedPointerOver}"
SelectedPressedBackground="{ThemeResource ListViewItemBackgroundSelectedPressed}"
SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected" />
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverSelected">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverPressed">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PressedSelected">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="DisabledStates">
<VisualState x:Name="Enabled" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="Root.RevealBorderThickness" Value="0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ListViewItemPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid>
<!-- Remove ItemContainerStyle to see the Reveal hover/click effect. -->
<ListView ItemContainerStyle="{StaticResource abc}" ItemsSource="{x:Bind Items}" />
</Grid>
</Page>
MainPage.xaml.cs
using System.Collections.Generic;
using Windows.UI.Xaml.Controls;
namespace BrokenRevealEffect
{
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
}
public List<string> Items => new List<string> { "Red", "Yellow", "Blue", "Green" };
}
}
我发现可以通过使用自定义样式重复 RevealBackgroundBrush
SystemControlTransparentRevealBackgroundBrush
和 ListViewItemRevealBackground
的定义来解决此问题。
<RevealBackgroundBrush
x:Key="SystemControlTransparentRevealBackgroundBrush"
FallbackColor="Transparent"
TargetTheme="Light"
Color="Transparent" />
<StaticResource x:Key="ListViewItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
只需在 Page.Resources
或 App.Resources
或 ResourceDictionary
中的自定义 ListViewItem
样式之前添加此代码;无论您在哪里定义样式。
对于为什么这是必要的,我没有合乎逻辑的解释。这些资源已在 generic.xaml
中定义,因此这不是必需的,但它确实解决了问题。我会把这归因于 Windows UI 库中的错误。