sfaust
sfaust

Reputation: 2363

Style triggers don't inherit?

I have a style with the following triggers defined:

<Style TargetType="{x:Type graphicElements:MyTabItem}" x:Key="StMyTabItemBase">
    <Setter Property="Foreground" Value="Black"/>
    <Setter Property="SelectedColor" Value="{Binding ApplicationColor, RelativeSource={RelativeSource AncestorType=graphicElements:MyTabControl}}" />
    <Setter Property="Expanded" Value="False" />
    <Setter Property="BorderBrush" Value="#FFACACAC"/>
    <Setter Property="Margin" Value="0"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="VerticalContentAlignment" Value="Top"/>
    <Setter Property="SnapsToDevicePixels" Value="False" />
    <Setter Property="Template" Value="{StaticResource CtTabCollapsed}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsSideBarExpanded, RelativeSource={RelativeSource AncestorType=graphicElements:MyTabControl}}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0" Duration="0">
                            <DiscreteBooleanKeyFrame Value="True" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0:0:0.25" Duration="0">
                            <DiscreteBooleanKeyFrame Value="False" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.ExitActions>
        </DataTrigger>
        <Trigger Property="Expanded" Value="True">
            <Setter Property="Template" Value="{StaticResource CtTabExpanded}" />
        </Trigger>
    </Style.Triggers>
</Style>

This works perfectly when I apply the direct style. However, I want to be able to create styles based on this style to override specific properties like margins and colors. I have tried to do so as follows (this creates a default based on this style):

<Style TargetType="{x:Type graphicElements:MyTabItem}" BasedOn="{StaticResource StMyTabItemBase}" />

However, as soon as I do that it no longer triggers or switches the template properly. If I copy just the triggers into the new style it works again, but I don't want to have to put the triggers into each style individually... Why aren't these inheriting like they are supposed to? Or do I misunderstand something about BasedOn and Triggers?

EDIT

Here is the 'BasedOn' style that works:

<Style TargetType="{x:Type graphicElements:AutodeskTabItem}" BasedOn="{StaticResource StAutodeskTabItemBase}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsSideBarExpanded, RelativeSource={RelativeSource AncestorType=graphicElements:AutodeskTabControl}}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0" Duration="0">
                            <DiscreteBooleanKeyFrame Value="True" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0:0:0.25" Duration="0">
                            <DiscreteBooleanKeyFrame Value="False" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.ExitActions>
        </DataTrigger>
        <Trigger Property="Expanded" Value="True">
            <Setter Property="Template" Value="{StaticResource CtTabExpanded}" />
        </Trigger>
    </Style.Triggers>
</Style>

Basically I just copied out the triggers portion of the base style. However I don't understand why I have to do that...

Upvotes: 0

Views: 443

Answers (1)

Andy
Andy

Reputation: 12276

I'm not sure about "supposed to" but your exit storyboard definitely won't find the first.
I recently came across this behaviour. It's an oddity to do with namescope. That won't work.
You could try starting another storyboard targeting the same property with 0 duration and hope that stops it. This did not work in my case.

The way I work round this in my app is to use a multiconverter to start and stop the storyboard.
My converter:

public class MultiAnimatorConverter : MarkupExtension, IMultiValueConverter
{
    public Storyboard sb { get; set; }

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        // 0 = Shape
        // 1 = Tag
        Shape shape = values[0] as Shape;
        if(shape.Tag.ToString() == "False")
        {
            sb.Stop(shape);
            sb.Remove(shape);
        }
        else
        {
            sb.Begin(shape, true);
        }
        return true;  // Abusing isenabled so I don't need another attached dependency property
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return null;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}

You may prefer an attached property to enabled. Useage:

<Setter Property="IsEnabled">
    <Setter.Value>
        <MultiBinding Converter="{ui:MultiAnimatorConverter sb={StaticResource MarchinAntsAnimation}}">
            <Binding RelativeSource="{RelativeSource Self}"/>
            <Binding Path="Tag" RelativeSource="{RelativeSource Self}"/>
        </MultiBinding>
    </Setter.Value>
</Setter>

My storyboard is a separate resource.

Storyboard.TargetProperty="(Shape.StrokeDashOffset)" RepeatBehavior="Forever" From="0" To="8" Duration="00:00:.8" Timeline.DesiredFrameRate="10" />

This is used in my Map Editor ( for our game ). The user is drawing the map for a scenario. They draw terrain. Woods, rivers, contours etc. All are polygons with different templates and I use basedon to inherit so all would get the same "marching ants" animation with dotted lines animated round them when the terrain is selected for editing.

Upvotes: 1

Related Questions