wpfxamltriggersstoryboardmultitrigger

ListBoxItem Style preserve MouseOver and Selected Style


I have a ListBox where I want to display the current State with a colored Rectangle sliding out.

When The Item is Selected or MouseOver the Recangle should extend otherwise it should shrink.

<ControlTemplate.Resources>
    <Storyboard x:Key="MoveOutStoryboard">
        <DoubleAnimation To="175"
                    Storyboard.TargetProperty="Width"
                    Storyboard.TargetName="AnimatingGrid">
            <DoubleAnimation.EasingFunction>
                <QuinticEase EasingMode="EaseOut" />
            </DoubleAnimation.EasingFunction>
        </DoubleAnimation>
        <ColorAnimation Storyboard.TargetName="ContentPresenter"
                Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"
                To="White" />
    </Storyboard>

    <Storyboard x:Key="MoveInStoryboard">
        <DoubleAnimation To="16"
                    Storyboard.TargetProperty="Width"
                    Storyboard.TargetName="AnimatingGrid">
            <DoubleAnimation.EasingFunction>
                <QuinticEase EasingMode="EaseOut" />
            </DoubleAnimation.EasingFunction>
        </DoubleAnimation>
        <ColorAnimation Storyboard.TargetName="ContentPresenter"
                Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"
                To="Black" />
    </Storyboard>
</ControlTemplate.Resources>

As there is no 'or' Multitrigger I figured out the following Trigger:

<ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
        <Trigger.EnterActions>
            <BeginStoryboard Storyboard="{StaticResource MoveOutStoryboard}" />
        </Trigger.EnterActions>
    </Trigger>

    <Trigger Property="IsSelected" Value="True">
        <Trigger.EnterActions>
            <BeginStoryboard Storyboard="{StaticResource MoveOutStoryboard}" />
        </Trigger.EnterActions>
    </Trigger>

    <MultiTrigger>
        <MultiTrigger.Conditions>
            <Condition Property="IsMouseOver" Value="False" />
            <Condition Property="IsSelected" Value="False" />
        </MultiTrigger.Conditions>

        <MultiTrigger.EnterActions>
            <BeginStoryboard Storyboard="{StaticResource MoveInStoryboard}" />
        </MultiTrigger.EnterActions>
    </MultiTrigger>
</ControlTemplate.Triggers>

But Somehow the MoveOutStoryboard is never called when I have the last MultiTrigger set, but I cannot figure out why.

Thanks for yor help.


Solution

  • since another animation can not take control over a property unless started by the same trigger, so give this a try

                <Trigger Property="IsMouseOver"
                         Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource MoveOutStoryboard}" />
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <BeginStoryboard Storyboard="{StaticResource MoveInStoryboard}" />
                    </Trigger.ExitActions>
                </Trigger>
                <Trigger Property="IsSelected"
                         Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource MoveOutStoryboard}" />
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <BeginStoryboard Storyboard="{StaticResource MoveInStoryboard}" />
                    </Trigger.ExitActions>
                </Trigger>
    

    if you face the issue with mouse over and IsSelected then use this

                <Trigger Property="IsMouseOver"
                         Value="True">
                    <Trigger.EnterActions>
                        <RemoveStoryboard BeginStoryboardName="moveIn2" />
                        <RemoveStoryboard BeginStoryboardName="moveOut2" />
                        <BeginStoryboard x:Name="moveOut1"
                                         Storyboard="{StaticResource MoveOutStoryboard}" />
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <RemoveStoryboard BeginStoryboardName="moveIn2" />
                        <RemoveStoryboard BeginStoryboardName="moveOut2" />
                        <BeginStoryboard x:Name="moveIn1"
                                         Storyboard="{StaticResource MoveInStoryboard}" />
                    </Trigger.ExitActions>
                </Trigger>
                <Trigger Property="IsSelected"
                         Value="True">
                    <Trigger.EnterActions>
                        <RemoveStoryboard BeginStoryboardName="moveIn1" />
                        <RemoveStoryboard BeginStoryboardName="moveOut1" />
                        <BeginStoryboard x:Name="moveOut2"
                                         Storyboard="{StaticResource MoveOutStoryboard}" />
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <RemoveStoryboard BeginStoryboardName="moveIn1" />
                        <RemoveStoryboard BeginStoryboardName="moveOut1" />
                        <BeginStoryboard x:Name="moveIn2"
                                         Storyboard="{StaticResource MoveInStoryboard}" />
                    </Trigger.ExitActions>
                </Trigger>
    

    also remove the multitrigger, that may not be necessary, or you can combine the remove storyboard approach in with your approach, that should work too.


    EDIT

    here is your approach with the RemoveStoryboard, this is working, I tested too

        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver"
                        Value="True">
                <Trigger.EnterActions>
                    <RemoveStoryboard BeginStoryboardName="multi" />
                    <RemoveStoryboard BeginStoryboardName="sel" />
                    <BeginStoryboard x:Name="over"
                                        Storyboard="{StaticResource MoveOutStoryboard}" />
                </Trigger.EnterActions>
            </Trigger>
    
            <Trigger Property="IsSelected"
                        Value="True">
                <Trigger.EnterActions>
                    <RemoveStoryboard BeginStoryboardName="multi" />
                    <RemoveStoryboard BeginStoryboardName="over" />
                    <BeginStoryboard x:Name="sel"
                                        Storyboard="{StaticResource MoveOutStoryboard}" />
                </Trigger.EnterActions>
            </Trigger>
    
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver"
                                Value="False" />
                    <Condition Property="IsSelected"
                                Value="False" />
                </MultiTrigger.Conditions>
    
                <MultiTrigger.EnterActions>
                    <RemoveStoryboard BeginStoryboardName="sel" />
                    <RemoveStoryboard BeginStoryboardName="over" />
                    <BeginStoryboard x:Name="multi"
                                        Storyboard="{StaticResource MoveInStoryboard}" />
                </MultiTrigger.EnterActions>
            </MultiTrigger>
        </ControlTemplate.Triggers>   
    



    or this, but this may be buggy and you can see some snaps in animation

        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver"
                        Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard x:Name="over"
                                        Storyboard="{StaticResource MoveOutStoryboard}" />
                </Trigger.EnterActions>
                <Trigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="over" />
                </Trigger.ExitActions>
            </Trigger>
    
            <Trigger Property="IsSelected"
                        Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard x:Name="sel"
                                        Storyboard="{StaticResource MoveOutStoryboard}" />
                </Trigger.EnterActions>
                <Trigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="sel" />
                </Trigger.ExitActions>
            </Trigger>
    
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver"
                                Value="False" />
                    <Condition Property="IsSelected"
                                Value="False" />
                </MultiTrigger.Conditions>
    
                <MultiTrigger.EnterActions>
                    <BeginStoryboard x:Name="multi"
                                        Storyboard="{StaticResource MoveInStoryboard}" />
                </MultiTrigger.EnterActions>
                <MultiTrigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="multi" />
                </MultiTrigger.ExitActions>
            </MultiTrigger>
        </ControlTemplate.Triggers>