我正在使用Windows 8样式(以前的Metro)创建一个WPF按钮。
我想按钮的焦点状态显示一个坚实的背景。当鼠标在控制,我想th的背景稍微变暗创建的视觉提示,按钮可以点击。
不幸的是,我下面写的XAML不起作用。聚焦状态显示正确,但当鼠标在控件上时,背景不会像我希望的那样变暗。
<Color x:Key="DoxCycleGreen">
#FF8DC63F
</Color>
<!-- Soft Interface : DoxCycle Green -->
<Color x:Key="DoxCycleGreenSoft">
#FFC0DC8F
</Color>
<Style x:Key="MetroButton" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="RootElement">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal" />
<VisualState Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundColor" Storyboard.TargetProperty="Color" To="{StaticResource DoxCycleGreen}" Duration="0:0:0.150" />
<ColorAnimation Storyboard.TargetName="FontColor" Storyboard.TargetProperty="Color" To="White" Duration="0:0:0.150" />
</Storyboard>
</VisualState>
<VisualState Name="Focused">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundColor" Storyboard.TargetProperty="Color" To="{StaticResource DoxCycleGreenSoft}" Duration="0:0:0.150" />
<ColorAnimation Storyboard.TargetName="FontColor" Storyboard.TargetProperty="Color" To="White" Duration="0:0:0.150" />
</Storyboard>
</VisualState>
<VisualState Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundColor" Storyboard.TargetProperty="Color" To="Transparent" Duration="0:0:0.150" />
<ColorAnimation Storyboard.TargetName="FontColor" Storyboard.TargetProperty="Color" To="{StaticResource DoxCycleGreen}" Duration="0:0:0.150" />
</Storyboard>
</VisualState>
<VisualState Name="Disabled">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderColor" Storyboard.TargetProperty="Color" To="DarkGray" Duration="0:0:0.1" />
<ColorAnimation Storyboard.TargetName="FontColor" Storyboard.TargetProperty="Color" To="DarkGray" Duration="0:0:0.1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="Transparent" >
<Border BorderThickness="1,1,1,1" Padding="2">
<Border.BorderBrush>
<SolidColorBrush x:Name="BorderColor" Color="{StaticResource DoxCycleGreen}"/>
</Border.BorderBrush>
<Border.Background>
<SolidColorBrush x:Name="BackgroundColor" Color="White"/>
</Border.Background>
<ContentPresenter
x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Content">
<TextBlock.Foreground>
<SolidColorBrush x:Name="FontColor" Color="{StaticResource DoxCycleGreen}"/>
</TextBlock.Foreground>
</ContentPresenter>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
3条答案
按热度按时间zaq34kh61#
我已经测试了你的代码。你现在有几个问题。但**主要问题是WPF控件一次只能处于特定状态组的一个Visual State中。**在像您在这里这样的情况下,控件可以 * 同时 * 聚焦和鼠标悬停,WPF必须选择要应用的状态(它不能应用两个状态,因为它们在同一个状态组中)。因此,在这种情况下,它只是将其保持在Focused状态,而不是将其发送到MouseOver状态。
一个控件 * 可以 * 处于多个状态,如果这些状态中的每一个都在 * 不同的 * 状态组中。this documentation:
每个VisualStateGroup都包含一个互斥的VisualState对象集合。也就是说,控件在每个VisualStateGroup中始终恰好处于的一种状态。
因此,我们纠正这段代码的第一步是包括适当的状态组,这将允许按钮能够显示其Focused状态,然后显示其MouseOver状态(其他可能性可以通过此更改进行纠正,但这是您特别注意到的一个,这是您以前的方法没有得到的)。
要做到这一点,我们需要小心地正确命名我们的状态组和(特别是)我们的状态名称。这是因为Button类内部的代码可能会调用
VisualStateManager.GoToState(this, "VerySpecificStateName", true);
(我没有检查Button类的实际源代码来验证这一点,但在编写了需要启动状态更改的自定义控件之后,我知道它一定是类似的东西)。为了获得我们需要的状态组和状态名称的列表,我们可以使用Expression Blend来“编辑”控件模板的副本(它将为我们填充所需的状态),或者找到它们here。该文档向我们显示,我们需要一个名为“FocusStates”的状态组,以及该组中名为“Focused”和“Unfocused”的两个状态(沿着其他状态组和状态)。顺便说一句,为了说明Button类如何通过这些特定的命名状态来启动其状态更改,如果您通过将“Focus”状态名称替换为“MisspelledFocus”来更改原始代码,您将看到按钮从未进入该状态。实现第一个更改,我们可能会得到如下结果:
这在一定程度上解决了问题。但是,如果您在Expression Blend中查看此内容,您会在状态组标题中注意到一个警告:
我们收到此警告是因为我们正在多个状态组中更改相同属性/对象对的值-在本例中是名为“BackgroundColor”的对象的“Color”属性。为什么这会成为一个问题?因为我前面说过的-如果这些状态位于不同的状态组中,则控件可以同时处于多个状态。因此,如果用户已经给予按钮焦点并且用户还将鼠标悬停在按钮上,则对于WPF来说,应用哪个动画可能是不明确的,因为两种状态都表示以不同的方式对相同的属性进行动画。
而且,第一个变化并没有完全得到我们想要的。如果你尝试给按钮焦点,然后悬停在它上面,它正确地从“正常”,到“焦点”,到“鼠标悬停”。但是如果你现在停止悬停,你会看到按钮不会返回到它的“焦点”状态。
有几种方法可以用来解决这个问题,并实现类似于您想要的东西,但作为一个例子,我们可以这样做。(这可能不是最干净的实现,但它修复了常见的对象/属性问题。
现在您将看到我们已经删除了WPF的二义性。我们看到它现在可以正确地处理从“Normal”到“Focus”到“MouseOver”再回到“Focus”的状态更改。
mv1qrgav2#
这是一个小编辑杰森的答案。事实证明,他使用两个ContentPresenters的方法打破了快捷键的操作。我做了一个小小的调整。。快捷键现在工作,但过渡动画不是很好…
pdkcd3nj3#
您需要检查
VisualStates
可用于特定Object,然后为所需状态设置Storyboard
。例如,MouseOver上的ComboBoxItem的状态为“Focused”,代码为:
对于其他对象,状态可能有不同的名称,如“MouseOver”、“PointerOver”等。
链接到文档here。