-->

WPF - Trigger to change Foreground and Background

2019-03-04 00:05发布

问题:

I am trying to do a RoutedEvent to activate ColorAnimation over a TextBlock and a Panel inside Buttons. My goal is to change the TextBlock's Foreground and the Panel's Background when using the MouseEnter and MouseLeave RoutedEvents.

The below code is actually working. But it works only when the mouse cursor is over one of these two objects (which makes sense).

I can't figure what should I do to activate both ColorAnimations when the mouse is over the Button (specially if it is not over the Panel or the TextBlock)

Here is an example of how the button looks like normal:

This is how the button looks like when I focus the Panel:

This is how the Button looks like when I focus himself (the Button background has the same color as the Panel's Background and the TextBlock's Foreground)

And this is how the button should looks like when the mouse is over the button

<UserControl.Resources>
<Style x:Key="Path" TargetType="Path">
    <Style.Triggers>
        <EventTrigger RoutedEvent="MouseEnter">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" To="White" Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="MouseLeave">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" To="Gray" Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
</Style>
<Style x:Key="TextBlock" TargetType="TextBlock">
    <Style.Triggers>
        <EventTrigger RoutedEvent="MouseEnter">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" To="White" Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="MouseLeave">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" To="Gray" Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
</Style>
</UserControl.Resources>

<Button Name="btnTest" 
        BorderThickness="0"
        Width="200"
        Height="200"
        Margin="5,5,0,0"
        VerticalAlignment="Top"
        >
    <Button.Triggers>
        <EventTrigger RoutedEvent="MouseEnter">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="Gray"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Button.Triggers>
    <StackPanel>
        <Path Style="{StaticResource Path}" Fill="Gray"
                Stretch="Fill" Width="98.851" Height="94.776"
                Data="M819.2,0H204.8C92,0,0,92.2,0,204.8v614.4C0,931.8,92,1024,204.8,1024h614.4c112.6,0,204.8-92.2,204.8-204.8V204.8  C1024,92.2,931.8,0,819.2,0z M879,337.8l-15.8,93L774.6,463.6L702,403.4l15.8-93.2l88.4-33L879,337.8z M786.2,594.8  c-61.601,22.8-129,7-180-35.399L217.8,831.2L128,702.8L528,423c-16.8-95.2,28.6-188.4,112.8-219.6c56.2-20.8,117.2-9.6,166.2,25  l-136,50.4L646.6,424L760,518l136-50.4C881.2,525.6,842.4,574,786.2,594.8z"
                />
        <TextBlock Style="{StaticResource TextBlock}" Margin="0,20,0,0" FontSize="15" FontWeight="Bold" Foreground="Gray" HorizontalAlignment="Center">
        TEST
        </TextBlock>
    </StackPanel>
</Button>

EDIT 1 I tested Ahmad's code, and it worked partially. When my cursor is over the Button, the DataTrigger works. But when I leave it (IsMouseOver = false) the Path Fill and the TextBlock Foreground are not changing back: OBS: I had to add DataTrigger.EnterActions to avoid the following error message:

A value of type 'BeginStoryBoard' cannot be added to a collection or dictionary of type 'SetterBaseCollection'.

<UserControl.Resources>
    <Style x:Key="Path" TargetType="Path">
        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" To="White" Duration="0:0:1"/>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="False">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" To="Gray" Duration="0:0:1"/>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    <Style x:Key="TextBlock" TargetType="TextBlock">
        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" To="White" Duration="0:0:1"/>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="False">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" To="Gray" Duration="0:0:1"/>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

回答1:

Instead of EventTrigger add a DataTrigger which binds to the Text/Panel UI elements ancestor

<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True">
    <BeginStoryboard>
         <Storyboard>
              <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" To="Gray" Duration="0:0:1"/>
         </Storyboard>
     </BeginStoryboard>
</DataTrigger>

other triggers for IsMouseOver being false ... 

You do this for both the Panel or the TextBlock and simply remove the trigger from the button and when the mouse is above the Button it will trigger and the text/panel storyboard.



回答2:

With Ahmad initial code, I did some research and I found the EnterActions and ExitActions properties. With a single DataTrigger, I can define my animations when the IsMouseOver is True

<Style x:Key="Path" TargetType="Path">
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=IsMouseOver}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" To="White" Duration="0:0:1"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" To="Gray" Duration="0:0:1"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.ExitActions>
        </DataTrigger>
    </Style.Triggers>
</Style>