Custom Visual State Triggers

In the previous blog I mentioned Adaptive Triggers. Adaptive Triggers allow you to activate a Visual State based upon the size of the application window. Yet, screen sizes aren’t the only things you may want to use as a trigger. You could use battery information, device family, internal application states, and internet connection.

This post is going to show you how to create a custom trigger, one that will set visual states based on internet connectivity. Let's start by showing you what we will achieve by the end of this post. 

When I am online, you will see

Then when I switch to airplane mode

The text and the square changes color.

Pretty simple right? So let's look at the code for this, in the MainPage.xaml I have

<Page
      x:Class="NetworkConnectionTriggerExample.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:NetworkConnectionTriggerExample"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <VisualStateManager.VisualStateGroups>
      <VisualStateGroup>

        <!-- Connected State -->
        <VisualState x:Name="ConnectedState">
          <VisualState.StateTriggers>
            <local:NetworkConnectionTrigger RequiresInternet="False" />
          </VisualState.StateTriggers>
          <VisualState.Setters>
            <Setter Target="StatusText.Text" Value="You are currently offline" />
            <Setter Target="StatusIcon.Fill" Value="Red" />
          </VisualState.Setters>
        </VisualState>

        <!-- Offline State -->
        <VisualState x:Name="OfflineState">
          <VisualState.StateTriggers>
            <local:NetworkConnectionTrigger RequiresInternet="True" />
          </VisualState.StateTriggers>
          <VisualState.Setters>
            <Setter Target="StatusText.Text" Value="You are currently online" />
            <Setter Target="StatusIcon.Fill" Value="Green" />
          </VisualState.Setters>
        </VisualState>
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <!-- User Interface with rectangle and text -->
    <StackPanel Orientation="Horizontal" 
                HorizontalAlignment="Center" 
                VerticalAlignment="Center">

      <Rectangle x:Name="StatusIcon" 
                 Fill="Green" 
                 Height="15" Width="15" 
                 VerticalAlignment="Center" 
                 Margin="10" />

      <TextBlock x:Name="StatusText" 
                 Text="You are currently online" 
                 FontSize="24" FontWeight="Light" />
    </StackPanel>
  </Grid>
</Page>

You can see that the root Grid on the page has a Visual State Manager with two Visual States - ConnectedState and OfflineState.  The trigger for these states is my custom NetworkConnectionTrigger. To determine when the state should be active I set the property RequiresInternet to true or false. Each state, when triggered, changes the text and the color of a status rectangle.

Now we have the user interface created, let's look at the code for the NetworkConnectionTrigger.

public class NetworkConnectionTrigger : StateTriggerBase
{
    private bool requiresInternet;

    public NetworkConnectionTrigger()
    {
        NetworkInformation.NetworkStatusChanged += NetworkInformationOnNetworkStatusChanged;
    }

    public bool RequiresInternet
    {
        get { return this.requiresInternet; }
        set
        {
            this.requiresInternet = value;
            if (NetworkInformation.GetInternetConnectionProfile() != null)
            {
                SetActive(value);
            }
            else
            {
                SetActive(!value);
            }
        }
    }

    private async void NetworkInformationOnNetworkStatusChanged(object sender)
    {
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            if (NetworkInformation.GetInternetConnectionProfile() != null)
            {
                SetActive(this.RequiresInternet);
            }
            else
            {
                SetActive(!this.RequiresInternet);
            }
        });
    }
}

As you can see the trigger is simple. First I have to derive from StateTriggerBase. To check for network connection changes I wire up to NetworkInformation.NetworkStatusChanged event.

The NetworkInformationOnNetworkStatusChanged method checks if the application has an internet connection using the NetworkInformation.GetInternetConnectionProfile() method. 

The RequiresInternet is a customer property I created, and, is what I set in the XAML to determine what criteria requires the state to be set to active. 

If I want to trigger the visual state I set the SetActive method to true, otherwise I set it to false.

That's all there is to it, you can find the source at https://github.com/shenchauhan/blog/tree/master/NetworkConnectionTriggerExample

I hope you've enjoyed this post.

Happy Coding!