【问题标题】:WPF Focused Visual State kicks in only when button pressed, why?WPF Focused Visual State 仅在按下按钮时才会启动,为什么?
【发布时间】:2014-05-12 03:18:37
【问题描述】:

关于下面的代码,谁能告诉我为什么当按钮处于正常状态和焦点状态时,按钮不反弹?换句话说,一个按钮不应该在它获得焦点状态时反弹,无论它是否被按下?

<Window x:Class="ButtonTemplateUsingVSM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="249" Width="619">
    <Window.Resources>

        <Style TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Background" Value="Black"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid RenderTransformOrigin=".5,.5">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup Name="CommonStates">
                                    <VisualState Name="Normal"/>
                                    <VisualState Name="MouseOver">
                                        <Storyboard>
                                            <ColorAnimation Storyboard.TargetName="outerCircle"
                                                            Storyboard.TargetProperty="(Ellipse.Fill).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)"
                                                            To="Orange" Duration="0:0:.4"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState Name="Pressed">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleX" To=".9" Duration="0"/>
                                            <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleY" To=".9" Duration="0"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState Name="Disabled">
                                        <Storyboard>
                                            <ColorAnimation Storyboard.TargetName="outerCircle"
                                                            Storyboard.TargetProperty="(Ellipse.Fill).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)"
                                                            To="Gray" Duration="0:0:.4"/>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup Name="FocusStates">
                                    <VisualState Name="Unfocused"/>
                                    <VisualState Name="Focused">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetProperty="(Grid.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
                                                             To="-20" AutoReverse="True" RepeatBehavior="Forever" Duration="0:0:.4">
                                                <DoubleAnimation.EasingFunction>
                                                    <QuadraticEase/>
                                                </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Grid.RenderTransform>
                                <TransformGroup>
                                    <ScaleTransform x:Name="scaleTransform"/>
                                    <TranslateTransform x:Name="translateTransform"/>
                                </TransformGroup>
                            </Grid.RenderTransform>
                            <Ellipse x:Name="outerCircle">
                                <Ellipse.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0"
                                                      Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}"/>
                                        <GradientStop x:Name="highlightGradientStop" Offset="1" Color="Red"/>
                                    </LinearGradientBrush>
                                </Ellipse.Fill>
                            </Ellipse>
                            <Ellipse RenderTransformOrigin=".5,.5">
                                <Ellipse.RenderTransform>
                                    <ScaleTransform ScaleX=".8" ScaleY=".8"/>
                                </Ellipse.RenderTransform>
                                <Ellipse.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0" Color="White"/>
                                        <GradientStop Offset="1" Color="Transparent"/>
                                    </LinearGradientBrush>
                                </Ellipse.Fill>
                            </Ellipse>
                            <Viewbox>
                                <ContentPresenter Margin="{TemplateBinding Padding}"/>
                            </Viewbox>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Window.Resources>
    <StackPanel Orientation="Horizontal">
        <Button Height="200" Width="200" FontSize="20" Padding="20" Margin="5">OK</Button>
        <Button Height="200" Width="200" FontSize="20" Padding="20" Margin="5">OK</Button>
        <Button Height="200" Width="200" FontSize="20" Padding="20" Margin="5">OK</Button>
        <Button Height="200" Width="200" FontSize="20" IsEnabled="False" Padding="20" Margin="5">OK</Button>
        <Button Height="200" Width="200" FontSize="20" Padding="20" Margin="5">OK</Button>
    </StackPanel>
</Window>

namespace ButtonTemplateUsingVSM
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

【问题讨论】:

    标签: wpf visualstates


    【解决方案1】:

    默认情况下,按钮仅在按下时才会获得焦点(除非您在代码中更改它)。您还可以获得键盘焦点。因此,您的弹跳动画仅在按下其中一个按钮时才会起作用,因为它仅设置为 Focused 状态:

    <VisualStateGroup Name="FocusStates">
        <VisualState Name="Unfocused"/>  <!--Right here-->
        <VisualState Name="Focused">
            <Storyboard>
                <DoubleAnimation Storyboard.TargetProperty="(Grid.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
                                 To="-20" AutoReverse="True" RepeatBehavior="Forever" 
                                 Duration="0:0:.4">
                    <DoubleAnimation.EasingFunction>
                        <QuadraticEase/>
                    </DoubleAnimation.EasingFunction>
                </DoubleAnimation>
            </Storyboard>
        </VisualState>
    </VisualStateGroup>
    

    如您所见,Unfocused VisualState 没有任何与之相关的动画。因此,除非其中一个按钮获得焦点,否则它不会反弹。根据MouseOverVisualState,它只会将颜色从红色变为橙色。

    我认为这对你来说是一本好书:MSDN Focus Overview

    编辑:

    在 cmets 中讨论的解释。

    XAML:

    <Window x:Class="Focus.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Content="Button 1" HorizontalAlignment="Center" Width="75" Margin="20" GotFocus="Button1_GotFocus"/>
            <Button Content="Button 2" HorizontalAlignment="Center" Width="75" GotFocus="Button2_GotFocus"/>
        </StackPanel>
    </Window>
    

    代码隐藏:

    using System.Windows;
    
    namespace Focus
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Button1_GotFocus(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Button 1 Focused");
            }
    
            private void Button2_GotFocus(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Button 2 Focused");
            }
        }
    }
    

    【讨论】:

    • 我的印象是这种情况——也就是说,一个按钮只有在按下时才处于焦点状态。但是这个例子取自“WPF 4 unleashed”一书,关于那个例子,有一个插图说明了所有的可能性(例如,MouseOver Unfocused、Disabled、Unfocused)。其中一种可能性是“Normal Focused”,这就是我发布这个问题的原因......在这种情况下,我不确定为什么提到“Normal Focused”作为用户交互可能导致的一种可能组合?
    • @WITL 我不知道正常的专注状态。一个按钮有两个状态组。 CommonStates:Normal、MouseOver、Pressed、Disabled 和 FocuStates:未聚焦、聚焦。这本书可能有错字……很多书都有。我没有这本书,所以我不知道它到底在说什么,但我告诉你的是它是怎样的。这是一个很好的州资源:blogs.msdn.com/b/jeetenk/archive/2009/07/10/…
    • 当您按下并释放按钮时,按钮处于 CommonStates- Normal 和 FocuStates-focused 状态,这可以是“Normal Focused”状态并且按钮仍会弹跳
    • @WITL 嗯...据我所知,这本书没有免费版本。在遇到麻烦之前删除该链接。但是,请阅读第 645 页底部的内容。它详细描述了我告诉您的内容。那么,当你鼠标悬停时会发生什么?它从正常状态进入鼠标悬停状态。如果按下按钮会发生什么?它从不专注的状态到专注的状态。当您将鼠标从按下的按钮上移开时会发生什么?它从 MouseOver 状态变为 Normal 状态,但是因为动画没有过渡,所以按钮会继续弹跳。
    • @WITL 因此,按钮只有在获得焦点时才会弹跳。您在问为什么它在 Normal Focused 状态下不反弹,但确实如此。我认为您对什么是 Focus 感到困惑。阅读我在回答中提供的链接,该链接告诉您有关 WPF 中的焦点。接收焦点的方式有很多种,但默认情况下,鼠标悬停不会接收到焦点。
    猜你喜欢
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 2013-05-04
    • 2017-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多