How to change "state"?

One thing I really just don’t get about this is that there seems to be no obvious notion of state. For example, I have a two panels on the screen. One is hidden with Opacity=“0” and the other is visible (state 1). When the visible panel is clicked I want the other panel to fade in (state 2).

If I use:

<Clicked>
	<Change panel.Opacity="1" Duration="1"/>
</Clicked>

then the panel fades in, yet of course it then just fades back out again 1s later.

So if I use:

<Clicked>
	<Set panel.Opacity="1"/>
</Clicked>

then the panel stays visible (as I want it to). Yet, it doesn’t fade in, it just appears.

So how can I fade in the panel on a click but have it stay visible as with <Set>?

And more generally, I feel like I’m just doing something wrong here in terms of the notion that the UI is moving from one state to another in that there’s no real representation of that state. I really just don’t understand how sequential states are represented and how to move from one state to another. Nor do I really understand how to reset a page to the original state when it’s visited again.

Thanks

There is a notion of a “rest state”. It’s how the initial UX is rendered without any deviation applied by triggers and/or user interaction.

Everything you do to the layout is then a “deviation from rest state”, which in the case of using Set is considered permanent (but you can still set it back from another Set), and Change is something that is only true while the enclosing trigger evaluates to true.

With the above in mind, there’s a simple conclusion: Change goes hand-in-hand with While*-triggers, while Set is commonly used with Pulse triggers (such as Clicked). You should avoid other combinations - in particular, Clicked + Change is a very bad idea.

Most, if not all, properties of visuals can be animated. Opacity is definitely one, so it’s just about getting it right. Here’s something that should get you started in the right direction:

<App>
    <WhileTrue ux:Name="showBlue">
        <Change theOrange.Opacity="0" Duration="0.32" />
        <Change theBlue.Opacity="1" Duration="0.32" />
    </WhileTrue>
    <StackPanel Alignment="VerticalCenter" ItemSpacing="4">
        <Panel ux:Name="theOrange" Width="240" Height="56" Color="#f81">
            <Text Value="Hide Me" Alignment="Center" TextColor="#fff" />
            <Clicked>
                <Toggle Target="showBlue" />
            </Clicked>
        </Panel>
        <Panel ux:Name="theBlue" Width="240" Height="56" Color="#18f" Opacity="0">
            <Text Value="No, hide me!" Alignment="Center" TextColor="#fff" />
            <Clicked>
                <Toggle Target="showBlue" />
            </Clicked>
        </Panel>
    </StackPanel>
</App>

As for how to reset a page to the original state, please see this thread.

Ok, thanks for this. It’s starting to make more sense now.

I’m now trying to change the width of something. So this works:

<WhileTrue Value="{working}">
	<Set button.Width="50"/>
</WhileTrue>

But what I really want is:

<WhileTrue Value="{working}">
	<Change button.Width="50" Duration="1"/>
</WhileTrue>

However, this doesn’t appear to change the width.
Is there a way to Change the width of something?

In this case, you want a LayoutAnimation to take care of animating the property. Change the target value from within the While* trigger, and describe how the element transitions from rest state to the deviation. Like so:

<App>
    <WhileTrue ux:Name="isLittle">
        <Change thePanel.Width="120" />
    </WhileTrue>
    <Panel ux:Name="thePanel" Alignment="Center" Width="240" Height="56" Color="#18f">
        <Clicked>
            <Toggle Target="isLittle" />
        </Clicked>
        <LayoutAnimation>
            <Resize RelativeTo="SizeChange" Vector="1" Duration="0.32" />
            <Move RelativeTo="PositionChange" Vector="1" Duration="0.32" />
        </LayoutAnimation>
    </Panel>
</App>

Alternatively, if you want to just make an element bigger or smaller relative to its original size, you can make use of Scale trigger directly inside WhileTrue, and no LayoutAnimation is required in that case (since Fuse already knows how to animate scaling):

<App>
    <WhileTrue ux:Name="isLittle">
        <Scale Target="thePanel" Factor="0.5" Duration="0.32" />
    </WhileTrue>
    <Panel ux:Name="thePanel" Alignment="Center" Width="240" Height="56" Color="#18f">
        <Clicked>
            <Toggle Target="isLittle" />
        </Clicked>
    </Panel>
</App>

Thanks for this. Using your example as a start I traced my problem…
It seems that if the panel width is not set to a concrete value (like 240 in your example) then Change does not work, eg.

<App>
    <WhileTrue ux:Name="isLittle">
        <Change thePanel.Width="50" />
    </WhileTrue>
    <Panel ux:Name="thePanel" Height="56" Color="#18f">
      <Clicked>
        <Toggle Target="isLittle" />
      </Clicked>
      <LayoutAnimation>
        <Resize RelativeTo="SizeChange" Vector="1" Duration="0.32" />
        <Move RelativeTo="PositionChange" Vector="1" Duration="0.32" />
      </LayoutAnimation>
    </Panel>
</App>

Does that sound correct?

If I set the width to 100% then Change does appear to work but the resized panel is the wrong size (it is bigger than it should be).

I would rather not have to set the width as I just want the panel to be the width of the parent. Note that if I set the width as width(parentPanel) then it works as expected.

Is this how it’s supposed to work?

So the problem in that case is conversion between units, which Change can not do. When you don’t set an explicit initial Width on the panel in question, it is essentially 100%, and that explains why it behaves like it does.

You can work around using width(parentPanel), like you found. Or you can look into using LayoutMaster to move the element between differently sized and positioned parents. In that case, the LayoutAnimation should take care about the transition just as fine.

Hope this helps!

Ok, yes that helps - I see why it doesn’t work now. I’ll also have a play with LayoutMaster.
Many thanks.