Press "Enter" to skip to content

Using State Machine in Xamarin Forms (Part 2)

In the first part of this series about State Machine, we covered the basics about it: how to set up and how to use the main features. In this part, we will cover Internal Transitions.

Understanding internal transition

When using a state machine, there are some scenarios where we want to do actions on a specific State without changing the state. For example, in a VideoPlayer, while the video is playing if we want to enable functionality such as Forward/Rewind we want to fire an action but also maintain the current state.

To achieve this, we can use internal transitions which allow adding transitions into a specific state. These transitions are fired by triggers, once fired they execute an action without changing the current state.

Let’s code it

First, we are going to add Forward and Rewind to the VideoTrigger enum.

public enum VideoTrigger
{
Play,
Stop,
Pause,
Forward,
Rewind
}

In the ViewModel, we add the internal transitions to the state machine for the Playing state. One for Rewind which will subtract 5 seconds from the video time and another one for Forward which will add 5 seconds.

public class MainViewModel : INotifyPropertyChanged {
...
public TimeSpan Position { get; set; }
public MainViewModel() {
...
_videoPlayerStateMachine.Configure(VideoState.Playing)
.OnActivate(OnStateEntry)
.OnEntry(OnStateEntry)
.Permit(VideoTrigger.Pause, VideoState.Paused)
.Permit(VideoTrigger.Stop, VideoState.Stopped)
.InternalTransition(VideoTrigger.Rewind, ()=> {
Position = Position.Subtract(TimeSpan.FromSeconds(5));
})
.InternalTransition(VideoTrigger.Forward, () => {
Position = Position.Add(TimeSpan.FromSeconds(5));
});
}
}

Finally, we add the buttons for Rewind and Forward to the UI.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
...>
<Label
Text="{Binding Position, StringFormat='{}{0:hh\\:mm\\:ss}'}"/>
<controls:VideoPlayer
AutoPlay="{Binding CanAutoPlay}"
Command="{Binding VideoActionCommand}"
Position="{Binding Position, Mode=TwoWay}"
Source="https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4"/>
<StackLayout
HorizontalOptions="CenterAndExpand"
Orientation="Horizontal">
<Button
Command="{Binding TriggerCommand}"
CommandParameter="{x:Static local:VideoTrigger.Play}"
IsVisible="{Binding CanPlay}" />
<Button
Command="{Binding TriggerCommand}"
CommandParameter="{x:Static local:VideoTrigger.Pause}"
IsVisible="{Binding CanPause}" />
<Button
Command="{Binding TriggerCommand}"
CommandParameter="{x:Static local:VideoTrigger.Stop}"
IsVisible="{Binding CanStop}"/>
<Button
Command="{Binding TriggerCommand}"
CommandParameter="{x:Static local:VideoTrigger.Rewind}"
IsVisible="{Binding CanStop}" />
<Button
Command="{Binding TriggerCommand}"
CommandParameter="{x:Static local:VideoTrigger.Forward}"
IsVisible="{Binding CanStop}" />
</StackLayout>
</StackLayout>
</ContentPage>

Result

That’s it for now, stay tuned for the next part where we’ll talk more about this topic. Check the full source code here.

Happy Stateless!