WPF - 使用带有动画的样式时没有 IsEnabled=true 行为

发布于 2024-07-23 08:44:31 字数 7569 浏览 6 评论 0原文

我在这里问了一个问题,但后来我意识到了我的问题不是代码,而是我用于按钮的样式。 由于问题与最初提出的问题完全不同,我认为如果我再次提出“正确”的问题,对其他用户会更有利。 我开始吧:

我在按钮中使用下面的模板。 当我设置button.IsEnabled=false时,它工作正常,但如果我设置button.IsEnabled=true,它就不会启用。 你能指出我做错了什么吗? 谢谢

<Style x:Key="BlackButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <ControlTemplate.Resources>
                    <Storyboard x:Key="MouseOverActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2F2F2F"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.1270000" Value="#FF2391FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="MouseOverDeactivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2391FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.2200000" Value="#FF2F2F2F"/>

                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="PressActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2391FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.1370000" Value="#FF48D6FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="PressedDeactivating" FillBehavior="Stop" >
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF48D6FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.2370000" Value="#FF2391FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="DisableActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFA7A7A7"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                </ControlTemplate.Resources>
                <Grid>
                    <Rectangle Stroke="Transparent" RadiusX="5" RadiusY="5" x:Name="rectangle">
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FF000000" Offset="0"/>
                                <GradientStop Color="#FF2F2F2F" Offset="1"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True" OpacityMask="{x:Null}"/>
                    <Rectangle Stroke="Transparent" RadiusX="5" RadiusY="5" x:Name="WhiteGlow">
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#5BFFFFFF" Offset="0"/>
                                <GradientStop Color="#00FFFFFF" Offset="0.5"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsCancel" Value="False"/>
                    <EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
                    <Trigger Property="IsFocused" Value="True">
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard2"/>
                        </Trigger.ExitActions>
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard1"/>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="IsDefaulted" Value="True"/>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverDeactivating}" x:Name="MouseOverDeactivating_BeginStoryboard"/>
                        </Trigger.ExitActions>
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard"/>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard x:Name="PressActivating_BeginStoryboard" Storyboard="{StaticResource PressActivating}"/>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard x:Name="PressedDeactivating_BeginStoryboard" Storyboard="{StaticResource PressedDeactivating}"/>
                        </Trigger.ExitActions>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource DisableActivating}" x:Name="DisableActivating_BeginStoryboard"/>
                        </Trigger.EnterActions>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I have asked a question here but then I realized my problem was not the code but the style I am using for a button. Since the problem is completely different than the one initially asked, I thought it would be more beneficial for other users if I just asked the "right" question again. Here I go:

I am using the template below in my button. When I set button.IsEnabled=false it works ok but if I set button.IsEnabled=true it doesn't get enabled. Can you please pinpoint what I am doing wrong?
Thanks

<Style x:Key="BlackButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <ControlTemplate.Resources>
                    <Storyboard x:Key="MouseOverActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2F2F2F"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.1270000" Value="#FF2391FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="MouseOverDeactivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2391FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.2200000" Value="#FF2F2F2F"/>

                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="PressActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2391FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.1370000" Value="#FF48D6FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="PressedDeactivating" FillBehavior="Stop" >
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF48D6FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.2370000" Value="#FF2391FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="DisableActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFA7A7A7"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                </ControlTemplate.Resources>
                <Grid>
                    <Rectangle Stroke="Transparent" RadiusX="5" RadiusY="5" x:Name="rectangle">
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FF000000" Offset="0"/>
                                <GradientStop Color="#FF2F2F2F" Offset="1"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True" OpacityMask="{x:Null}"/>
                    <Rectangle Stroke="Transparent" RadiusX="5" RadiusY="5" x:Name="WhiteGlow">
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#5BFFFFFF" Offset="0"/>
                                <GradientStop Color="#00FFFFFF" Offset="0.5"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsCancel" Value="False"/>
                    <EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
                    <Trigger Property="IsFocused" Value="True">
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard2"/>
                        </Trigger.ExitActions>
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard1"/>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="IsDefaulted" Value="True"/>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverDeactivating}" x:Name="MouseOverDeactivating_BeginStoryboard"/>
                        </Trigger.ExitActions>
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard"/>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard x:Name="PressActivating_BeginStoryboard" Storyboard="{StaticResource PressActivating}"/>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard x:Name="PressedDeactivating_BeginStoryboard" Storyboard="{StaticResource PressedDeactivating}"/>
                        </Trigger.ExitActions>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource DisableActivating}" x:Name="DisableActivating_BeginStoryboard"/>
                        </Trigger.EnterActions>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

罪歌 2024-07-30 08:44:31

最简单的选择是添加动画 IsEnabled 触发 ExitAction,这将恢复 EnterAction 中的动画

The easiest option is to add an animation the the IsEnabled trigger ExitAction that will revert the animation in the EnterAction

绅士风度i 2024-07-30 08:44:31

我怀疑您所看到的行为是当 IsEnabled 变为 false 时您使用的动画的结果。 DependencyProperties 实际上具有与其关联的优先级,其中动画位于列表的较高位置; 该层次结构来自 MSDN,是:

  • 属性系统强制
  • 活动动画,或具有保持行为的动画。
  • 本地价值
  • TemplatedParent 模板属性
  • 隐式样式
  • 样式触发器
  • 模板触发器
  • 样式设置器
  • 默认(主题)样式
  • 继承自父级
  • 依赖属性元数据的默认值

默认情况下,动画具有 FillBehavior 的 HoldEnd,这意味着它们停留在动画结束时的值。 当 IsEnabled 通过绑定变为 True 时,该更新优先发生在“本地值”级别,并且由于 DisableActivating 故事板将外观保持在更高的优先级(“具有保持行为的动画”),因此您永远不会看到一旦按钮第一次改变,按钮就会改变。

对此有三种解决方案:

  1. 更新动画以具有 Stop 的 FillBehavior,这意味着一旦动画停止,动画将不会断言“IsEnabled=False”视觉效果。 您需要一个标准的非动画触发器,其状态与动画结束时的状态相同,以便在动画完成后继续断言这一点,否则您只会看到它恢复到动画开始时的状态。 由于它只是一个触发器集,因此当本地值更新时,您会看到它像您期望的那样返回到原始值。 此外,由于动画具有更高的优先级,因此您可以设置样式并同时启动动画,并且仅在动画完成后“看到”样式的影响(因此您的淡入淡出将按预期工作)。
  2. 您可以创建一个新的触发器,该触发器在 IsEnabled 为 True 时应用,以动画方式(可能立即)返回到原始状态,而不是更改 FillBehavior。 这也可以通过在触发器的 ExitAction 中应用动画来完成。 由于它也是一个动画,但稍后应用,因此它将覆盖其他动画的 HoldEnd 状态。 从某种意义上说,这比选项 1 更容易,但维护向前和向后动画可能会变得很麻烦,特别是如果您不需要反向动画来实现特定的视觉效果; 但是,您可能希望使其保持淡入和淡出禁用状态。
  3. 将 ExitAction 添加到 IsEnabled 触发器以停止故事板,防止动画继续断言其在动画结束时具有的值,以便可以应用本地值样式。 此选项的优点是不必重复样式(如#1),同时也不必反转动画(如#2)。

在这三种解决方案中,最后一种可能是架构上最干净的(除非您有特定的原因,例如需要淡入和淡出,更喜欢其他选项之一 - 或上述选项的组合)。

I suspect that the behaviour you are seeing is a result of the animation you use when IsEnabled becomes false. DependencyProperties actually have a precedence associated to them, in which animations are high up on the list; that hierarchy, from MSDN, is:

  • Property system coercion
  • Active animations, or animations with a Hold behavior.
  • Local value
  • TemplatedParent template properties
  • Implicit style
  • Style triggers
  • Template triggers
  • Style setters
  • Default (theme) style
  • Inherited from parent
  • Default value from dependency property metadata

By default, animations have a FillBehavior of HoldEnd, which means that they stay at the value that the animation ended at. When IsEnabled becomes True through your binding, that update occurs at the 'Local value' level in the precedence, and since the DisableActivating storyboard is holding the appearance at a higher level of precedence ('animations with a Hold behavior'), you never see the button change once it has changed the first time.

There are three solutions to this:

  1. Update your animation to have a FillBehavior of Stop, which means that the animation will not assert the 'IsEnabled=False' visual once the animation stops. You'll need a standard, non-animated trigger with the same state as the end of the animation to continue to assert this once the animation completes, as otherwise you'll just see it revert back to the state it was when the animation began. Since it's just a trigger set, when the local value is updated you'll see it return to the original value like you expect. Also, since the animation is of higher precedence, you can set the style and start the animation simultaneously and only "see" the affects of the style once the animation completes (so your fade will work as expected).
  2. Instead of changing the FillBehavior, you can create a new trigger that applies when IsEnabled is True that animates (perhaps instantaneously) back to the original state. This can also be done by applying an animation in the trigger's ExitAction. Since it's also an animation but was applied later, it will override the HoldEnd state of the other animation. In some sense, this is easier that option 1, but it can become a hassle to maintain a forward and reverse animation, especially if you don't need the reverse animation for a specific visual effect; you may want to keep it to fade in and out the disabled state, however.
  3. Add an ExitAction to your IsEnabled trigger to stop the storyboard, preventing the animation from continuing to assert the value it had at the end of the animation so that the local value style can be applied. This option has the benefits of not having to repeat the style (as in #1) while also not having to reverse the animation (as in #2).

Of the three solutions, the last one is probably the cleanest architecturally (unless you have a specific reason, like needing to fade both in and out, to prefer one of the other options - or a combination of the options above).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文