WPF - Нет IsEnabled = истинное поведение с использованием стиля с анимацией - PullRequest
1 голос
/ 08 июня 2009

Я задал вопрос здесь , но потом понял, что моя проблема не в коде, а в стиле, который я использую для кнопки. Поскольку проблема полностью отличается от той, которая была задана изначально, я подумал, что для других пользователей будет более полезно, если я просто задам «правильный» вопрос еще раз. Вот и я:

Я использую шаблон ниже в моей кнопке. Когда я устанавливаю 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>

Ответы [ 2 ]

1 голос
/ 09 июня 2009

Самый простой вариант - добавить анимацию триггера IsEnabled ExitAction, которая будет возвращать анимацию в EnterAction

0 голосов
/ 09 июня 2009

Я подозреваю, что поведение, которое вы видите, является результатом анимации, которую вы используете, когда IsEnabled становится ложным. DependencyProperties на самом деле имеет приоритет, связанный с ними, в котором анимации находятся высоко в списке; эта иерархия из MSDN :

  • Принуждение системы собственности
  • Активные анимации или анимации с поведением Hold.
  • Местное значение
  • Свойства шаблона TemplatedParent
  • Неявный стиль
  • Стиль триггеров
  • Шаблон триггеров
  • Установщики стиля
  • Стиль по умолчанию (тема)
  • Наследуется от родителя
  • Значение по умолчанию из метаданных свойства зависимостей

По умолчанию анимации имеют FillBehavior HoldEnd, что означает, что они остаются на значении, при котором анимация закончилась. Когда IsEnabled становится True благодаря вашей привязке, это обновление происходит на уровне «Локальное значение» в приоритете, и поскольку раскадровка DisableActivating поддерживает внешний вид с более высоким уровнем приоритета («анимации с поведением удержания»), вы никогда не увидите кнопка меняется, как только она изменилась в первый раз.

Для этого есть три решения:

  1. Обновите вашу анимацию, чтобы иметь FillBehavior of Stop, что означает, что анимация не будет утверждать визуальный элемент «IsEnabled = False» после остановки анимации. Вам понадобится стандартный неанимированный триггер с тем же состоянием, что и в конце анимации, чтобы продолжать утверждать это после завершения анимации, иначе вы просто увидите, что он возвращается к состоянию, в котором он был, когда началась анимация. , Поскольку это просто набор триггеров, при обновлении локального значения оно вернется к исходному значению, как вы ожидаете. Кроме того, поскольку анимация имеет более высокий приоритет, вы можете установить стиль и запустить анимацию одновременно и только «увидеть» влияние стиля после завершения анимации (поэтому ваше затухание будет работать так, как ожидается).
  2. Вместо изменения FillBehavior, вы можете создать новый триггер, который применяется, когда IsEnabled равен True, который оживляет (возможно, мгновенно) обратно в исходное состояние. Это также можно сделать, применив анимацию в ExitAction триггера. Так как это также анимация, но она была применена позже, она переопределит состояние HoldEnd другой анимации. В некотором смысле, это проще, чем вариант 1, но это может стать проблемой для поддержания прямой и обратной анимации, особенно если вам не нужна обратная анимация для определенного визуального эффекта; однако вы можете захотеть, чтобы он постепенно исчезал в и из отключенного состояния.
  3. Добавьте ExitAction к своему триггеру IsEnabled, чтобы остановить раскадровку, не позволяя анимации продолжать утверждать значение, которое она имела в конце анимации, чтобы можно было применить стиль локальных значений. Эта опция имеет то преимущество, что не нужно повторять стиль (как в # 1), а также нет необходимости изменять анимацию (как в # 2).

Из трех решений последнее, вероятно, является наиболее чистым с архитектурной точки зрения (если только у вас нет конкретной причины, например, необходимость постепенного исчезновения как изнутри, так и снаружи, чтобы выбрать один из других вариантов - или комбинацию из перечисленных выше вариантов).

...