Xamarin.Forms Visual States with View Models

In my previous post, Visual States in Xamarin.Forms using BuildIt.Forms, I showed how to use BuildIt.Forms (https://www.nuget.org/packages/BuildIt.Forms) to create visual states that can be used to define how the user interface changes to reflect different states of the page. The example demonstrated switching between visual states in the code behind with calls to VisualStateManager.GoToState. In this post I’m going to extend the example to allow the states to be switched from a view model.

I’ll start by creating a view model that will be data bound to the page. Usually I’d use a framework like MvvmCross to drive the view model/view instantiation but for this example I’ll keep it simple. I will however still put the view model in a separate project – again this promotes good separation between the view models and their associated view. I’ll create a new .NET Standard library, FormsWithStates.Core, and add a reference to it into the FormsWithStates.UI project.

image

I’ll add a new class to the project, MainViewModel, which will be the view model for the MainPage of the application. To track states within the view model, I need to add a reference to the BuildIt.States library on NuGet.

image

The MainViewModel will define a simple property WelcomeText to demonstrate that the view model is indeed data bound to the page. It also implements the interface IHasStates which defines a property StateManager – you can think of the IStateManager implementation as an object that can track states and state transitions.

public enum SampleStates
{
     Base,
     Show,
     Hide
}


public class MainViewModel : IHasStates
{
     public IStateManager StateManager { get; } = new StateManager();


    public string WelcomeText => “Welcome to Forms!”;


    public MainViewModel()
     {
         StateManager.Group<SampleStates>().DefineAllStates();
     }


    public void Show()
     {
         StateManager.GoToState(SampleStates.Show);
     }
     public void Hide()
     {
         StateManager.GoToState(SampleStates.Hide);
     }
}

The enumeration SampleStates defines the states that the MainViewModel references – both the enumeration and the states themselves have to match the names of the visual state group and visual states defined in the XAML for the page. The final step is to link the visual states on the page to the IStateManager instance, so that when there is a state change in the IStateManager, it will be reflected on the page via a change to the visual states. This is done by the Bind method on the VisualStateManager class.

public partial class MainPage : ContentPage
{
     private MainViewModel ViewModel { get; } = new MainViewModel();
     public MainPage()
     {
         InitializeComponent();


        BindingContext = ViewModel;
         VisualStateManager.Bind(this, ViewModel.StateManager);
     }


    public void ShowClicked(object sender, EventArgs e)
     {
         ViewModel.Show();
     }
     public void HideClicked(object sender, EventArgs e)
     {
         ViewModel.Hide();
     }
}

Whilst from the perspective of a user, there is no difference (since the Show and Hide buttons do the same thing), state management has been shifted to the view model where it can be tested. This separation of views and view models is important to ensure all application logic can be tested.

Leave a comment