Dazy Jackson
Dazy Jackson

Reputation: 85

WPF button EventTrigger=Button.IsEnabledChanged

I want to animate a color change of a button (based on its IsEnabled property) in two ways:

  1. when it is changed from enabled to disables -> the color will be changed from white to black.
  2. when it is changed from disabled to enabled -> the color will be changed from black to white.

I am trying to use EventTrigger with RoutedEvent, but there is only one event named Button.IsEnabledChanged.

I have a button that its IsEnabled property is changed based on a logic state. The state machine is working, but I want to change the color (using ColorAnimation) of the button when it becomes enabled or disabled.

What is the best way to do so?

Upvotes: 1

Views: 7101

Answers (2)

ActualRandy
ActualRandy

Reputation: 306

I wish you could have used an EventTrigger, but they only work for routed events. The event you would have used, "IsEnabledChanged", is not a routed event, so you can't use an EventTrigger. However, there is another method, where you use the VisualStateManager and provide your own animation for the Disabled and Normal states.

Instead of using the VisualStateManager, you could have performed your animation in your code-behind, and possibly you could have declared your own custom RoutedEvent. My solution, using the VisualStateManager, has the advantage that it is performed entirely in XAML.

To use VisualStateManager, you will create a style with a ControlTemplate, my research has not uncovered any other way. That requires you to build most of your button's display features. Here is a screen shot of the enabled and disabled states of my sample:

ScreenShot.jpg![Screenshot showing the enabled and disabled states

To mimic the normal button appearance, I used two rectangles, one on above the other, for the button's appearance. Look on the left above: where you see the dark gray top of the button, that comes from one of my rectangles, and the black bottom part comes from my other rectangle. The disabled appearance on the right uses the same two rectangles, but the animation changes the colors to White and WhiteSmoke. I supply a ColorAnimation for each rectangle.

Here is the style that uses the VisualStateManager:

<Window.Resources>
    <Style TargetType="Button" x:Key="AnimatedStyle" >
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <!-- Define our button's border. Note that
                         the text color is inherited by child 
                         elements, that is we give it a name, so 
                         we can target it with the animation -->
                    <Border BorderBrush="Black" BorderThickness="1" 
                            CornerRadius="2" 
                            TextBlock.Foreground="WhiteSmoke" 
                            Name="theBorder">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>

                            <!-- To match the appearance of a typical button, 
                                 we use two rectangles -->
                            <Rectangle Name="topBackground" Fill="DarkGray"/>
                            <Rectangle Grid.Row="1" Name="bottomBackground" 
                                       Fill="Black" />

                             <!-- The content presenter shows the 
                                  button's text -->
                            <ContentPresenter Grid.RowSpan="2" 
                                      VerticalAlignment="Center" 
                                      HorizontalAlignment="Center" />
                        </Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup Name="CommonStates">

                                <!-- Here is where we define 
                                    the disable animation -->
                                <VisualState Name="Disabled">
                                    <Storyboard>
                                        <ColorAnimation 
                                              Storyboard.TargetName="topBackground"
                                              Storyboard.TargetProperty="(Rectangle.Fill).(Color)"
                                              To="White" Duration="0:0:.5" />
                                        <ColorAnimation 
                                              Storyboard.TargetName="bottomBackground"
                                              Storyboard.TargetProperty="(Rectangle.Fill).(Color)"
                                              To="WhiteSmoke" Duration="0:0:0.5" />
                                        <ColorAnimation 
                                              Storyboard.TargetName="theBorder"
                                              Storyboard.TargetProperty="(TextBlock.Foreground).(Color)"
                                              To="Gray" Duration="0:0:0.5" />
                                    </Storyboard>
                                </VisualState>

                                <!-- Here is where the enabled animation 
                                     is defined -->
                                <VisualState Name="Normal">
                                    <Storyboard>
                                        <ColorAnimation 
                                              Storyboard.TargetName="topBackground"
                                              Storyboard.TargetProperty="(Rectangle.Fill).Color"
                                              To="DarkGray" Duration="0:0:0.5" />
                                        <ColorAnimation 
                                              Storyboard.TargetName="bottomBackground"
                                              Storyboard.TargetProperty="(Rectangle.Fill).(Color)"
                                              To="Black" Duration="0:0:0.5" />
                                        <ColorAnimation 
                                              Storyboard.TargetName="theBorder"
                                              Storyboard.TargetProperty="(TextBlock.Foreground).Color"
                                              To="WhiteSmoke" Duration="0:0:0.5" />
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

Here is some XAML to utilize the style and demonstrate the animation in action:

<Grid>
     <!--The button uses the style from above. Note that we control 
         whether it is enabled by binding the Enabled property to the checkbox's 
         property 'IsChecked', that way we don't need
         any code-behind -->
    <Button Content="Test Button" Name="btnTest" 
            IsEnabled="{Binding ElementName=chkEnabled,Path=IsChecked}" 
            Height="30" Margin="5" 
            Click="btnTest_Click"
            Style="{StaticResource AnimatedStyle}" />

    <CheckBox Grid.Column="1" Content="Enable Button" 
              Name="chkEnabled" IsChecked="True" VerticalAlignment="Center" />

    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="auto" />
    </Grid.ColumnDefinitions>
</Grid>

Finally, just to prove that the button really is disabled/enabled, here is the entire code-behind (other than boiler-plate code), which is fired by clicking the button, but only when it is enabled:

    private void btnTest_Click(object sender, RoutedEventArgs e) {
        MessageBox.Show("You clicked the button, it must be enabled.");
    }

Upvotes: 0

keith
keith

Reputation: 3110

Define a style such as the following:

<Style x:Key="ButtonEnabledStyle" TargetType="Button">
        <Setter Property="Background" Value="White" />
        <Style.Triggers>
            <Trigger Property="IsEnabled" Value="false" >
                <Setter Property="Background" Value="Black" />
            </Trigger>
        </Style.Triggers>
    </Style>

Then assign it to your button(s) like this:

<Button Content="I'm a button" Style="{StaticResource ButtonEnabledStyle}" />

Upvotes: 0

Related Questions