Triggering State Changes in BuildIt.States

The state management capability that BuildIt.Lifecycle uses is actually provided by a standalone library BuildIt.States which focusses on tracking states and allowing transitions between states. BuildIt.Lifecycle builds on this to adapt it to generating view models for specific states, along with the glue that connects states and transitions to the appropriate platform implementation (eg Pages and Navigation). The nice thing about the state management library being separate is that it can iterate independently. In this case, we’ve updated the library to include support for triggers.

One of the new features added to the Universal Windows Platform (UWP) for Windows 10, are state triggers. Out of the box, UWP comes with an AdaptiveTrigger class which is used to trigger a state change once a minimum width or height (or both) have been reached by a Window. The way triggers work is that they evaluate a particular condition and once the condition has been met, the IsActive property is changed to true. Once all triggers for a particular state are set to IsActive, the framework changes the active visual state. We’ve adapted this concept to apply it to state management within the BuildIt.States library.

Taking the FlickrViewer application that I discussed in my post, Building a Flickr Viewer App with BuildIt.Lifecycle, I’ll modify the MainViewModel to use triggers. Here you’ll see that in addition to adding triggers to the state definition, we’re also making use of an instance of the LoadingManager. A common scenario is to have states for when data is being loaded, and when it has been loaded. To handle this, the state management library includes a LoadingManager class which tracks which page/viewmodel state is used for both Loading and Loaded states. The nice artefact of using the LoadingManager is that the MainViewModel doesn’t explicitly need to indicate when it’s loading or not loading data. Instead it simply wraps the loading operation in a using statement. Behind the scenes this links to the LoadingTrigger instances used in the state declaration.

public enum MainStates
{
    Base,
    Loading,
    Loaded
}

LoadingManager<MainStates> LoadingManager { get; } = new LoadingManager<MainStates>()
{
    LoadingState = MainStates.Loading,
    LoadedState = MainStates.Loaded
};

public MainViewModel(IFlickrService flickr)
{

    StateManager
        .Group<MainStates>()
        .DefineState(MainStates.Loading)
            .AddTrigger(new LoadingTrigger<MainStates>(LoadingManager) {ActiveValue = MainStates.Loading})
        .DefineState(MainStates.Loaded)
            .AddTrigger(new LoadingTrigger<MainStates>(LoadingManager) {ActiveValue = MainStates.Loaded});
    Flickr = flickr;
}

public async Task Load()
{

    using (LoadingManager.Load())
    {
        var photos = await Flickr.LoadPhotos();
        photos.DoForEach(Photos.Add);
    }         
}

Leave a comment