Navigation using BuildIt.Lifecycle

In my post, Getting Started with BuildIt.Lifecycle, I showed how to get started with BuildIt.Lifecycle. The next step is to add basic navigation between pages/views. To do this, we need to change our mindset to again think of this as a state transition. Before I cover what I mean by this, let’s add two buttons to our Home page that we’ll use to trigger the navigation to either the Settings or About pages.

<StackPanel VerticalAlignment=”Center”
            HorizontalAlignment=”Center”>
    <TextBlock Text=”Main Page” FontSize=”40″ />
    <Button Click=”SettingsClick”>Settings</Button>
    <Button Click=”AboutClick”>About</Button>
</StackPanel>

As you can see from the XAML there are event handlers wired up to the Click event on each of the Buttons. In each of the event handlers we simply route a call to a corresponding method on the ViewModel.

private MainViewModel ViewModel => DataContext as MainViewModel;

private void SettingsClick(object sender, RoutedEventArgs e)
{
    ViewModel.DisplaySettings();
}

private void AboutClick(object sender, RoutedEventArgs e)
{
    ViewModel.DisplayAbout();
}

Now we need to think about what displaying either the Settings or the About page means in the context of our application state. When the application is launched the PrimaryRegion transitions to the AppStates.Home state, which correlates to the HomePage being displayed. When the user clicks on either button, what we want the application to do is to transition from the Home state to the either the Settings or About state, depending on which button the user clicks.

Unlike some other frameworks where you can navigate from one ViewModel to another ViewModel by calling a base method such as ShowViewModel or call Navigate on some sort of Navigation wrapper, the HomeViewModel doesn’t actually know anything about the states of region (this is the responsibility of the StateManager that’s part of the PrimaryRegion). Instead, what the HomeViewModel has to do is to raise an event signalling that an event has occurred that it needs assistance dealing with. So the implementation for DisplaySettings and DisplayAbout becomes:

public event EventHandler ShowSettings;
public event EventHandler ShowAbout;
public void DisplaySettings()
{
    ShowSettings.SafeRaise(this);
}
public void DisplayAbout()
{
    ShowAbout.SafeRaise(this);
}

Note: SafeRaise is a helper method defined in BuildIt.General but with the new features in C# 6 you could also write this as:

ShowAbout?.Invoke(this,EventArgs.Empty);

With the HomeViewModel raising these events, we need to subscribe to them somewhere so that the PrimaryRegion can trigger the state change on its StateManager to go to either the Settings or About states. This is done by wiring and unwiring event handlers as part of the state transitions into and from the Home state:

sm.DefineViewModelState<MainViewModel>(AppStates.Home)
    .WhenChangedTo(vm =>
    {
        vm.ShowSettings += ChangeToSettings;
        vm.ShowAbout += ChangeToAbout;
    })
    .WhenChangingFrom(vm =>
    {
        vm.ShowSettings -= ChangeToSettings;
        vm.ShowAbout -= ChangeToAbout;
    });

And then it’s just a matter of implementing the ChangeToSettings and ChangeToAbout methods which just need to invoke a state change on the StateManager.

private async void ChangeToAbout(object sender, EventArgs e)
{
    await StateManager.GoToState(AppStates.About);
}

private async void ChangeToSettings(object sender, EventArgs e)
{
    await StateManager.GoToState(AppStates.Settings);
}

And we’re done; now when the user clicks on either the Settings or the About buttons, the PrimaryRegion will trigger the state change, which will in turn navigate to the corresponding page.

Leave a comment