WPF - MultiTrigger in ControlTemplate, strange behaviour

EightyOne Unite picture EightyOne Unite · Oct 7, 2009 · Viewed 9.9k times · Source

Okay, I've not done much WPF lately and this is confusing me.

I have a Style defined for RadioButton, which uses a ControlTemplate with a MultiTrigger. The gist is that I want a Border to become opaque when the mouse either hovers over it or when it's IsChecked is true.

So I have the MultiTrigger, which animates the Opacity in and out operating on 2 conditions; IsChecked is false and IsMouseOver is true. I've then got another 3 triggers. One set's the cursor to hand when the mouse is over it. Another set's the borders opacity to 0 when it's IsChecked is false and a final one to set opacity to 1 when IsChecked is true.

My problem is that that final trigger doesn't work the way I'm expecting. The RadioButton which is checked no longer satisfies the conditions for the MultiTrigger so the animations don't happen but the border's opacity goes back to 0 when I click.

Something has to be goind on with the MultiTrigger because commenting it out makes the other trigger work.

The code for the Style is below -

    <Style TargetType="RadioButton" x:Key="MenuFlameButton">
    <Setter Property="Width" Value="80"/>
    <Setter Property="FontFamily" Value="/#SlabTallX"/>
    <Setter Property="FontSize" Value="16"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="RadioButton">
                <Grid>
                    <Border                             
                    BorderThickness="1,0,1,0"
                    BorderBrush="{StaticResource XWhiteX}">
                    </Border>
                    <Border x:Name="outerBorder" 
                        Background="{TemplateBinding Background}"
                        OpacityMask="{StaticResource TallVerticalMask}">
                    </Border>
                    <ContentControl
                    HorizontalContentAlignment="Center"
                    VerticalContentAlignment="Center">
                        <TextBlock x:Name="txt" Style="{StaticResource ButtonText}" IsHitTestVisible="False"
                               Text="{TemplateBinding Content}"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Center"/>
                    </ContentControl>
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition SourceName="outerBorder" Property="UIElement.IsMouseOver" Value="True"/>
                            <Condition Property="RadioButton.IsChecked" Value="False"/>
                        </MultiTrigger.Conditions>
                        <MultiTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.EnterActions>
                        <MultiTrigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="0"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.ExitActions>
                    </MultiTrigger>
                    <Trigger Property="UIElement.IsMouseOver" Value="True">
                        <Setter Property="Cursor" Value="Hand"/>
                    </Trigger>
                    <Trigger Property="RadioButton.IsChecked" Value="False">
                        <Setter TargetName="outerBorder" Property="Opacity" Value="0"/>
                    </Trigger>
                    <Trigger Property="RadioButton.IsChecked" Value="True">
                        <Setter TargetName="outerBorder" Property="Opacity" Value="1"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I'm really not sure why the border fades back out when I click it.

As always, any help will be greatly appreciated.

EDIT: I've included a Kaxaml friendly snippet to make it a bit easier for people to help. Just paste this code in.

<Page.Resources>
    <Style x:Key="MainWindow" TargetType="Window">
        <Setter Property="Height" Value="600"/>
        <Setter Property="Height" Value="600"/>
        <Setter Property="Height" Value="600"/>
        <Setter Property="Height" Value="600"/>
        <Setter Property="Height" Value="600"/>
    </Style>
    <Style x:Key="SplashScreenWindow" TargetType="Window">
        <Setter Property="Height" Value="200"/>
        <Setter Property="Width" Value="450"/>
        <Setter Property="AllowsTransparency" Value="True"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="ResizeMode" Value="NoResize"/>
        <Setter Property="Opacity" Value="1"/>
    </Style>

    <Style x:Key="ActivityBorder" TargetType="Border">
        <Setter Property="BorderThickness" Value="0,0,0,1"/>
        <Setter Property="Background" Value="#0555"/>
        <Setter Property="BorderBrush" Value="#999"/>
        <Setter Property="Margin" Value="10,3,10,3"/>
    </Style>


    <Style x:Key="Title" TargetType="TextBlock">
        <Setter Property="FontFamily" Value="/#Harabara"/>
        <Setter Property="FontSize" Value="42"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Foreground" Value="#eee"/>
    </Style>
    <Style x:Key="SplashTitle" BasedOn="{StaticResource Title}" TargetType="TextBlock">
        <Setter Property="FontSize" Value="56"/>
    </Style>
    <Style x:Key="SubTitle" TargetType="TextBlock">
        <Setter Property="FontFamily" Value="/#SlabTallX"/>
        <Setter Property="FontSize" Value="24"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Foreground" Value="#eee"/>
        <Setter Property="Margin" Value="10"/>
    </Style>
    <Style x:Key="DescriptionText" TargetType="TextBlock">
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Foreground" Value="#eee"/>
        <Setter Property="Margin" Value="5,5,5,15"/>
    </Style>
    <Style x:Key="Strap" TargetType="TextBlock">
        <Setter Property="FontFamily" Value="/#SlabTallX"/>
        <Setter Property="FontSize" Value="17"/>
        <Setter Property="Foreground" Value="#ccc"/>
    </Style>
    <Style x:Key="StrapActive" TargetType="TextBlock">
        <Setter Property="FontFamily" Value="/#SlabTallX"/>
        <Setter Property="FontSize" Value="17"/>
        <Setter Property="Foreground" Value="#fff"/>
    </Style>
    <Style x:Key="StrapBold" TargetType="TextBlock">
        <Setter Property="FontFamily" Value="/#SlabTallX"/>
        <Setter Property="FontSize" Value="17"/>
        <Setter Property="Foreground" Value="#cc9"/>
    </Style>
    <Style x:Key="ButtonText" BasedOn="{StaticResource Strap}" TargetType="TextBlock">
        <Setter Property="FontSize" Value="14"/>
    </Style>
    <Style x:Key="FormLabel" TargetType="Label">
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Foreground" Value="#ccc"/>
        <Setter Property="Width" Value="200"/>
        <Setter Property="Margin" Value="5,5,10,5"/>
    </Style>
    <Style x:Key="StatusLabel" TargetType="Label">
        <Setter Property="FontSize" Value="15"/>
        <Setter Property="Foreground" Value="#ccc"/>
        <Setter Property="Margin" Value="0,-5,0,0"/>
    </Style>
    <Style x:Key="StatusText" TargetType="TextBlock">
        <Setter Property="FontSize" Value="13"/>
        <Setter Property="Foreground" Value="#cc9"/>
        <Setter Property="Margin" Value="5,-2,0,0"/>
        <Setter Property="TextWrapping" Value="Wrap"/>
        <Setter Property="Foreground" Value="#cc9"/>
    </Style>
    <Style x:Key="FormTextBox" TargetType="TextBox">
        <Setter Property="Width" Value="250"/>
        <Setter Property="Height" Value="25"/>
    </Style>
    <Style x:Key="PageBorder" TargetType="Border">
        <Setter Property="Padding" Value="10,0,10,10"/>
        <Setter Property="BorderThickness" Value="2"/>
    </Style>
<RadialGradientBrush x:Key="GreyRadial" Center="0,0" RadiusX="1" RadiusY="1">
    <GradientStop Color="#555" Offset="0"/>
    <GradientStop Color="#333" Offset="1"/>
</RadialGradientBrush>

<LinearGradientBrush x:Key="StripBorderDarkGrey" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#222" Offset="0"/>
    <GradientStop Color="#111" Offset=".25"/>
    <GradientStop Color="#444" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="StripBorderDarkRed" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#222" Offset="0"/>
    <GradientStop Color="#111" Offset=".25"/>
    <GradientStop Color="#644" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="TitleBar" StartPoint="0,0" EndPoint="0,1">
    <GradientStop Color="#777" Offset="0"/>
    <GradientStop Color="#555" Offset=".3"/>
    <GradientStop Color="#777" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlame" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#f00" Offset="0"/>
    <GradientStop Color="#0f00" Offset="0.15"/>
    <GradientStop Color="#f0f" Offset="0.25"/>
    <GradientStop Color="#0f0f" Offset="0.35"/>
    <GradientStop Color="#00f" Offset="0.5"/>
    <GradientStop Color="#000f" Offset="0.62"/>
    <GradientStop Color="#0f0" Offset="0.75"/>
    <GradientStop Color="#00f0" Offset="0.85"/>
    <GradientStop Color="#ff0" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="XWhiteX" StartPoint="0,0" EndPoint="0,1">
    <GradientStop Color="Transparent" Offset="0"/>
    <GradientStop Color="#ddd" Offset="0.5"/>
    <GradientStop Color="Transparent" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameRed" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#f00" Offset="0"/>
    <GradientStop Color="#0f00" Offset="0.15"/>
    <GradientStop Color="#f00" Offset="0.25"/>
    <GradientStop Color="#0f00" Offset="0.35"/>
    <GradientStop Color="#f00" Offset="0.5"/>
    <GradientStop Color="#0f00" Offset="0.62"/>
    <GradientStop Color="#f00" Offset="0.75"/>
    <GradientStop Color="#0f00" Offset="0.85"/>
    <GradientStop Color="#f00" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlamePurple" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#f0f" Offset="0"/>
    <GradientStop Color="#0f0f" Offset="0.15"/>
    <GradientStop Color="#f0f" Offset="0.25"/>
    <GradientStop Color="#0f0f" Offset="0.35"/>
    <GradientStop Color="#f0f" Offset="0.5"/>
    <GradientStop Color="#0f0f" Offset="0.62"/>
    <GradientStop Color="#f0f" Offset="0.75"/>
    <GradientStop Color="#0f0f" Offset="0.85"/>
    <GradientStop Color="#f0f" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameBlue" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#00f" Offset="0"/>
    <GradientStop Color="#000f" Offset="0.15"/>
    <GradientStop Color="#00f" Offset="0.25"/>
    <GradientStop Color="#000f" Offset="0.35"/>
    <GradientStop Color="#00f" Offset="0.5"/>
    <GradientStop Color="#000f" Offset="0.62"/>
    <GradientStop Color="#00f" Offset="0.75"/>
    <GradientStop Color="#000f" Offset="0.85"/>
    <GradientStop Color="#00f" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameGreen" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#0f0" Offset="0"/>
    <GradientStop Color="#00f0" Offset="0.15"/>
    <GradientStop Color="#0f0" Offset="0.25"/>
    <GradientStop Color="#00f0" Offset="0.35"/>
    <GradientStop Color="#0f0" Offset="0.5"/>
    <GradientStop Color="#00f0" Offset="0.62"/>
    <GradientStop Color="#0f0" Offset="0.75"/>
    <GradientStop Color="#00f0" Offset="0.85"/>
    <GradientStop Color="#0f0" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameYellow" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#ff0" Offset="0"/>
    <GradientStop Color="#0ff0" Offset="0.15"/>
    <GradientStop Color="#ff0" Offset="0.25"/>
    <GradientStop Color="#0ff0" Offset="0.35"/>
    <GradientStop Color="#ff0" Offset="0.5"/>
    <GradientStop Color="#0ff0" Offset="0.62"/>
    <GradientStop Color="#ff0" Offset="0.75"/>
    <GradientStop Color="#0ff0" Offset="0.85"/>
    <GradientStop Color="#ff0" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameSectionRed" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#0f00" Offset="0"/>
    <GradientStop Color="#f00" Offset="0.5"/><!--red-->
    <GradientStop Color="#0f00" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameSectionPurple" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#0f0f" Offset="0"/>
    <GradientStop Color="#f0f" Offset="0.5"/><!--purple-->
    <GradientStop Color="#0f0f" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameSectionBlue" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#000f" Offset="0"/>
    <GradientStop Color="#00f" Offset="0.5"/><!--blue-->
    <GradientStop Color="#000f" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameSectionGreen" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#00f0" Offset="0"/>
    <GradientStop Color="#0f0" Offset="0.5"/><!--green-->
    <GradientStop Color="#00f0" Offset="1"/>

</LinearGradientBrush>

<LinearGradientBrush x:Key="ColorFlameSectionYellow" StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="#0ff0" Offset="0"/>
    <GradientStop Color="#ff0" Offset="0.5"/><!--yellow-->
    <GradientStop Color="#0ff0" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="ShortVerticalMask" StartPoint="0,1" EndPoint="0,0">
    <GradientStop Color="#6FFF" Offset="0"/>
    <GradientStop Color="Transparent" Offset="0.25"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="VerticalMask" StartPoint="0,1" EndPoint="0,0">
    <GradientStop Color="#6FFF" Offset="0"/>
    <GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="TallVerticalMask" StartPoint="0,1" EndPoint="0,0">
    <GradientStop Color="#6FFF" Offset="0"/>
    <GradientStop Color="Transparent" Offset="0.9"/>
</LinearGradientBrush>
</Page.Resources>



<DockPanel x:Name="menuDock" DockPanel.Dock="Top" LastChildFill="False" Background="Black">

<DockPanel.Resources>
    <Style TargetType="RadioButton" x:Key="MenuFlameButton">
    <Setter Property="Width" Value="80"/>
    <Setter Property="FontFamily" Value="/#SlabTallX"/>
    <Setter Property="FontSize" Value="16"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="RadioButton">
                <Grid>
                    <Border                             
                    BorderThickness="1,0,1,0"
                    BorderBrush="{StaticResource XWhiteX}">
                    </Border>
                    <Border x:Name="outerBorder"  
                        Background="{TemplateBinding Background}"
                        OpacityMask="{StaticResource TallVerticalMask}">
                    </Border>
                    <ContentControl
                    HorizontalContentAlignment="Center"
                    VerticalContentAlignment="Center">
                        <TextBlock x:Name="txt" Style="{StaticResource ButtonText}" IsHitTestVisible="False"
                               Text="{TemplateBinding Content}"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Center"/>
                    </ContentControl>
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition SourceName="outerBorder" Property="UIElement.IsMouseOver" Value="True"/>
                            <Condition Property="RadioButton.IsChecked" Value="False"/>
                        </MultiTrigger.Conditions>
                        <MultiTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.EnterActions>
                        <MultiTrigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="outerBorder" Storyboard.TargetProperty="(UIElement.Opacity)" To="0"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.ExitActions>
                    </MultiTrigger>

                    <Trigger Property="UIElement.IsMouseOver" Value="True">
                        <Setter Property="Cursor" Value="Hand"/>
                    </Trigger>
                    <Trigger Property="RadioButton.IsChecked" Value="False">
                        <Setter TargetName="outerBorder" Property="Opacity" Value="0"/>
                    </Trigger>
                    <Trigger Property="RadioButton.IsChecked" Value="True">
                        <Setter TargetName="outerBorder" Property="Opacity" Value="1"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

</DockPanel.Resources>
    <RadioButton
        Margin="2,0,10,0"
        Background="{StaticResource ColorFlameSectionYellow}"
        Content="Tools"
        DockPanel.Dock="Right"
        Style="{StaticResource MenuFlameButton}"
        Tag="Tools"/>
    <RadioButton
        Margin="2,0,2,0"
        Background="{StaticResource ColorFlameSectionGreen}"
        Content="Settings"
        DockPanel.Dock="Right"
        Style="{StaticResource MenuFlameButton}"
        Tag="Settings"/>
    <RadioButton
        Margin="2,0,2,0"
        Background="{StaticResource ColorFlameSectionBlue}"
        Content="Event Log"
        DockPanel.Dock="Right"
        Style="{StaticResource MenuFlameButton}"
        Tag="EventLog"/>
    <RadioButton
        Margin="2,0,2,0"
        Background="{StaticResource ColorFlameSectionPurple}"
        Content="Queue"
        DockPanel.Dock="Right"
        Style="{StaticResource MenuFlameButton}"
        Tag="Queue"/>
    <RadioButton
        Margin="2,0,2,0"
        Background="{StaticResource ColorFlameSectionRed}"
        Content="Debug"
        DockPanel.Dock="Right"
        Style="{StaticResource MenuFlameButton}"
        Tag="Debug"/>
</DockPanel>

Answer

Stephen picture Stephen · Apr 12, 2012

Here is a solution, I modified outerBorder to specify Opacity=0:

<Border x:Name="outerBorder" Background="{TemplateBinding Background}" OpacityMask="{StaticResource TallVerticalMask}" Opacity="0">
                            </Border>

Named the ExitAction's storyboard:

<MultiTrigger.ExitActions>
    <BeginStoryboard Name="ExitStoryBoard">
    ...

And replaced the triggers for RadioButton.IsChecked with this:

    <Trigger Property="RadioButton.IsChecked" Value="True">
            <Trigger.EnterActions>
                    <PauseStoryboard BeginStoryboardName="ExitStoryBoard"/>
            </Trigger.EnterActions>
            <Trigger.Setters>
                    <Setter TargetName="outerBorder" Property="Opacity" Value="1"/>
            </Trigger.Setters>
            <Trigger.ExitActions>
                    <ResumeStoryboard BeginStoryboardName="ExitStoryBoard"/>
            </Trigger.ExitActions>
    </Trigger>