0
votes

I'm trying to make a AppBarButton in UWP that fades in when it becomes visible.

To do this, I copied the AppBarButton style and added another VisualStateGroup with triggers from the WindowsStateTriggers nuget package.

<ControlTemplate TargetType="AppBarButton">
    <Grid x:Name="Root" MinWidth="{TemplateBinding MinWidth}" MaxWidth="{TemplateBinding MaxWidth}" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}" Margin="1,0">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisibilityStates">
                <VisualState x:Name="Hidden">
                    <VisualState.Setters>
                        <Setter Target="ContentRoot.Opacity" Value="0"/>
                    </VisualState.Setters>
                    <VisualState.StateTriggers>
                        <windowsStateTriggers:EqualsStateTrigger Value="{Binding ElementName=Root, Path=Visibility}" EqualTo="Hidden"/>
                    </VisualState.StateTriggers>
                </VisualState>
                <VisualState x:Name="Visible">
                    <VisualState.Storyboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="Opacity"
                                             From="0" To="1.0" Duration="0:0:1" />
                        </Storyboard>
                    </VisualState.Storyboard>
                    <VisualState.StateTriggers>
                        <windowsStateTriggers:EqualsStateTrigger Value="{Binding ElementName=Root, Path=Visibility}" EqualTo="Visible"/>
                    </VisualState.StateTriggers>
                </VisualState>
            </VisualStateGroup>

The problem is trying to trigger using Visibility. With the above code, when the control is first made visible, the entire app pauses for a second and then the fade in animation runs. Then on subsequent visibility changes, the animation no longer runs.

I'm guessing the problem is the EqualsStateTrigger, as using the built in AdaptiveTrigger with some arbitrary windows size, I can trigger everything fine.

Questions:

  • What trigger should I be using here?
  • Is there a way to change the VisualState for this group from the Page XAML instead?
  • Is there some other method to doing this that doesn't require the control template to be rewritten? I know for WPF there was a Transistionz library from SciChart but I can't find one for UWP.
1
Why not custom AppBarButton and start animation when the Visibility property change method ? - CoCaIceDew
For creating property change watcher you could refer this case reply. - CoCaIceDew
@CoCaIceDew That is what the above code is trying to do - it is part of the AppBarButton template. I ended up getting it working - the binding for the Trigger should have been {Binding RelativeSource={RelativeSource TemplatedParent}, Path=Visibility}. Do you know another way to start the storyboard on Visibility change? UWP doesn't have DataTrigger like WPF. - geometrikal

1 Answers

0
votes

(see update at end)

To answer my own question, the main problem with the above code was the binding. It should be {Binding RelativeSource={RelativeSource TemplatedParent}, Path=Visibility}. Also, the "Hidden" visual state is not necessary. e.g

 <VisualStateGroup x:Name="VisibilityStates"><VisualState x:Name="Visible">
                <VisualState.Storyboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="Opacity"
                                         From="0" To="1.0" Duration="0:0:1" />
                    </Storyboard>
                </VisualState.Storyboard>
                <VisualState.StateTriggers>
                    <windowsStateTriggers:EqualsStateTrigger Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Visibility}" EqualTo="Visible"/>
                </VisualState.StateTriggers>
            </VisualState>
        </VisualStateGroup>

This method involves editing the control template. If you don't want to do that, you can put the VisualStateGroup under the first Grid element (it won't work directly under Page) and have multiple animations targeting the different buttons, and the trigger put under the control to which the visibility of the other buttons depends. E.g.

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="MultiSelect">
            <VisualState x:Name="Checked">
                <VisualState.Storyboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="buttonSelectAll" Storyboard.TargetProperty="Opacity"
                                         From="0" To="1.0" Duration="0:0:0.3" />
                        <DoubleAnimation Storyboard.TargetName="buttonClearAll" Storyboard.TargetProperty="Opacity"
                                         From="0" To="1.0" Duration="0:0:0.3" />
                    </Storyboard>
                </VisualState.Storyboard>
                <VisualState.Setters>
                    <Setter Target="buttonSelectAll.Visibility" Value="Visible" />
                    <Setter Target="buttonClearAll.Visibility" Value="Visible" />
                </VisualState.Setters>
                <VisualState.StateTriggers>
                    <windowsStateTriggers:EqualsStateTrigger Value="{Binding ElementName=buttonSelect, Path=IsChecked}" EqualTo="True"/>
                </VisualState.StateTriggers>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

Update

This can also be achieved with CompositionAnimations via the Windows Community Toolkit