How to animate button on IsEnabled property changed?

195 views Asked by At

I'm currently styling a button template in WPF .NET Core 3.1 in a resource dictionary and I want to fade the button color when the button's IsEnabled property is set to true/false. According to this link it appears we can easily do this with Trigger.Enter/ExitActions. However, I can't seem to get it to work.

I've tried a few variations:

<Trigger Property="IsEnabled" Value="True">
   <Trigger.EnterActions>
       <BeginStoryboard>
           <Storyboard>
              <ColorAnimation Storyboard.TargetName="border"
                              Storyboard.TargetProperty="Background.Color"
                              Duration="0:0:0.3"
                              To="{StaticResource ButtonGray}"/>
           </Storyboard>
       </BeginStoryboard>
   </Trigger.EnterActions>
</Trigger>

Putting it all in one trigger:

<Trigger Property="IsEnabled" Value="false">
   <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.BackgroundBrush}"/>
   <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.BorderBrush}"/>
   <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.ForegroundBrush}"/>
   <Trigger.ExitActions>
      <BeginStoryboard>
          <Storyboard>
              <ColorAnimation Storyboard.TargetName="border"
                              Storyboard.TargetProperty="Background.Color"
                              Duration="0:0:0.3"
                              To="{StaticResource ButtonGray}"/>
           </Storyboard>
      </BeginStoryboard>
  </Trigger.ExitActions>
</Trigger>

Finally, I tried where the trigger has both EnterActions and ExitActions in the same trigger. Any idea why this isn't working?

UPDATE: Whole Button Style:

<Style TargetType="{x:Type Control}" x:Key="ControlBase">
    <Setter Property="FontFamily" Value="Poppins"/>
</Style>

<!-- Gray Button Styles -->
<Color x:Key="SmallButtonGray">#BB222222</Color>
<SolidColorBrush x:Key="SmallButtonGrayBrush" Color="{StaticResource SmallButtonGray}"/>

<Color x:Key="Button.Hover.BGGray">#BB333333</Color>
<SolidColorBrush x:Key="Button.Hover.BGGrayBrush" Color="{StaticResource Button.Hover.BGGray}"/>

<Color x:Key="Button.Click.Gray">#BB888888</Color>
<SolidColorBrush x:Key="Button.Click.GrayBrush" Color="{StaticResource Button.Click.Gray}"/>

<Color x:Key="Button.Disabled.Background">#44BBBBBB</Color>
<SolidColorBrush x:Key="Button.Disabled.BackgroundBrush" Color="{StaticResource Button.Disabled.Background}"/>

<Color x:Key="Button.Disabled.Border">#FFADB2B5</Color>
<SolidColorBrush x:Key="Button.Disabled.BorderBrush" Color="{StaticResource Button.Disabled.Border}"/>

<Color x:Key="Button.Disabled.Foreground">#FF838383</Color>
<SolidColorBrush x:Key="Button.Disabled.ForegroundBrush" Color="{StaticResource Button.Disabled.Foreground}"/>

<!-- Small Button Styles -->
<Style x:Key="SmallButtonStyle" TargetType="Button" BasedOn="{StaticResource ControlBase}">
    <Setter Property="SnapsToDevicePixels" Value="True"/>
    <Setter Property="FontWeight" Value="Light" />
    <Setter Property="FontSize" Value="18"/>
    <Setter Property="TextOptions.TextFormattingMode" Value="Display" />
    <Setter Property="TextOptions.TextRenderingMode" Value="ClearType"/>
    <Setter Property="UseLayoutRounding" Value="True"/>
    <Setter Property="BorderThickness" Value="1"/>
</Style>

<!-- Page Buttons-->
<Style x:Key="GrayButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallButtonStyle}">
    <Setter Property="Background" Value="{StaticResource SmallButtonGrayBrush}"/>
    <Setter Property="Foreground" Value="{StaticResource BGWhiteBrush}"/>
    <Setter Property="BorderBrush" Value="{StaticResource FGBlackBrush}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ButtonBase}">
                <Border x:Name="border" 
                            Background="{TemplateBinding Background}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            BorderBrush="{TemplateBinding BorderBrush}" 
                            SnapsToDevicePixels="false"         
                            RenderTransformOrigin="0.5,0.5"
                            RenderOptions.BitmapScalingMode="HighQuality">
                        <ContentPresenter x:Name="contentPresenter" Focusable="False" 
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                          Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" 
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    <Border.RenderTransform>
                        <ScaleTransform/>
                    </Border.RenderTransform>
                </Border>
                <ControlTemplate.Triggers>
                    <!-- Button Mouse Hover Animation -->
                    <EventTrigger RoutedEvent="MouseEnter">
                        <BeginStoryboard>
                            <Storyboard >
                                <ColorAnimation Storyboard.TargetName="border"
                                                Storyboard.TargetProperty="Background.Color"
                                                To="{StaticResource Button.Hover.BGGray}"
                                                Duration="0:0:0.3" />
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
                                                 To="1.05"
                                                 Duration="0:0:0.3"/>
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
                                                 To="1.05"
                                                 Duration="0:0:0.3"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="MouseLeave">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation To="{StaticResource ButtonGray}"
                                                        Duration="0:0:0.4"
                                                        Storyboard.TargetName="border"
                                                        Storyboard.TargetProperty="Background.Color"/>
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
                                                 To="1"
                                                 Duration="0:0:0.3"/>
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
                                                 To="1"
                                                 Duration="0:0:0.3"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    
                    <!-- Button Mouse Click Animation -->
                    <EventTrigger RoutedEvent="PreviewMouseDown">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="border"
                                                Storyboard.TargetProperty="Background.Color"
                                                To="{StaticResource Button.Click.Gray}"
                                                Duration="0:0:0.2"/>
                                
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
                                                 To="1"
                                                 Duration="0:0:0.1"/>
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
                                                 To="1"
                                                 Duration="0:0:0.1"/>

                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="PreviewMouseUp">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="border"
                                                Storyboard.TargetProperty="Background.Color"
                                                To="{StaticResource Button.Hover.BGGray}"
                                                Duration="0:0:0.1"/>
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
                                                 Duration="0:0:0.1"
                                                 To="1.05"/>
                                <DoubleAnimation Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
                                                 Duration="0:0:0.1"
                                                 To="1.05"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    
                    <!-- Not Enabled -->
                    <Trigger Property="IsEnabled" Value="false">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="border"
                                                    Storyboard.TargetProperty="Background.Color"
                                                    Duration="0:0:0.3"
                                                    To="{StaticResource Button.Disabled.Background}"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="border"
                                                    Storyboard.TargetProperty="Background.Color"
                                                    Duration="0:0:0.3"
                                                    To="{StaticResource SmallButtonGray}"/>
                      
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                    </Trigger>
                    
                    <!-- Enabled -->
                    <!-- Fade back into normal colors -->

                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
1

There are 1 answers

3
EldHasp On BEST ANSWER

For debugging purposes, I modified the template to see the property values of the brush instance in the Backgroud property you are trying to animate.

                <ControlTemplate TargetType="{x:Type ButtonBase}">
                    <Border x:Name="border" 
                            Background="{TemplateBinding Background}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            BorderBrush="{TemplateBinding BorderBrush}" 
                            SnapsToDevicePixels="false"         
                            RenderTransformOrigin="0.5,0.5"
                            RenderOptions.BitmapScalingMode="HighQuality">
                        <StackPanel>
                            <TextBlock Text="{Binding Background.Color, ElementName=border}"/>
                            <TextBlock Text="{Binding Background.IsFrozen, ElementName=border}"/>
                        </StackPanel>
                        <!--<ContentPresenter x:Name="contentPresenter" Focusable="False" 
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                          Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" 
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>-->
                    </Border>
                    <ControlTemplate.Triggers>

Information was displayed that the SolidColorBrush instance (SmallButtonGrayBrush resource) was frozen. But frozen instances are immutable.

This happens because SmallButtonGrayBrush and SmallButtonGray resources are retrieved using StaticResource. If you receive resources using DynamicResource, then the instances are not frozen and the animation works.

    <!-- Gray Button Styles -->
    <Color x:Key="SmallButtonGray">#BB222222</Color>
    <SolidColorBrush x:Key="SmallButtonGrayBrush" Color="{DynamicResource SmallButtonGray}"/>
    <!-- Page Buttons-->
    <Style x:Key="GrayButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallButtonStyle}">
        <Setter Property="Background" Value="{DynamicResource SmallButtonGrayBrush}"/>