Windows 10 Universal Apps - Adaptive Triggers
Written by Mike James   
Thursday, 09 April 2015
Article Index
Windows 10 Universal Apps - Adaptive Triggers
Custom Triggers

Custom Triggers

You can create your own triggers by creating a custom class inheriting from StateTriggerBase. All you have to do is set up a dependency property that the trigger is going to use as its condition and call SetTriggerValue with true or false depending on whether or not the condition is satisfied. 

To see this in action lets us create a new AdaptiveTrigger which corresponds to the XAML tag:

 <MyTrigger myCondition="10" />

The idea is that we need to create a Class called MyTrigger with a dependency property corresponding to myCondition. When the myCondition property changes you can compare its value to any other value you care to use - the day of the month or the model number of the device etc. If your condition is satisfied i.e. it is the tenth day of the month then you call SetTriggerValue(true) and SetTriggerValue(false) otherwise. 

Notice that this scheme only checks the trigger when myCondition is changed not when the day of the month changes. This means that the trigger will usually only be checked once when the application starts. If you want to check for changes in another value such as day of the month you need to hook into its changed event.  

 

If you are puzzled by what is going on in creating the MyTrigger class see - How XAML works - Creating Objects With XAML.

All we need is to create a public MyTrigger class that registered a suitable dependency property that is set as the "condition" in the trigger tag. We need to use a dependency property because we need an onChanged event and handler and this is part of the standard behavior of a dependency property. 

If you need to find out about dependency properties see: Inside Dependency Properties.

For simplicity add the MyTrigger Class to the project using Add,New Item.  The class has to inherit from StateTriggerBase : 

public class MyTrigger : StateTriggerBase
{

and to make this work we also need to add:

using Windows.UI.Xaml;

We next need to set up a dependency property associated with the CLR property myCondition:public int myCondition:

{
 get { return
        (int) GetValue(MyConditionProperty); }
 set { SetValue(MyConditionProperty, value); }
}

 As is always the case the dependency property has the same name but with Property tagged onto the end.

Next we need to register the dependency property and in this case we need an OnChanged event handler.

public static readonly DependencyProperty MyConditionProperty = DependencyProperty.Register(
   "myCondition",
   typeof(int),
   typeof(MyTrigger),
   new PropertyMetadata(true,
                       OnMyConditionChanged));

That is more or less all we have to do, but to give the new Trigger some sort of behavior we need the OnChanged handler to do something. For simplicity, let's just activate the trigger if the value set is greater than 50: 

private static void OnMyConditionChanged(
    DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
 MyTrigger obj = (MyTrigger)d;
 if ((int) e.NewValue > 50) {
  obj.SetTriggerValue(true);
 }else
 {
  obj.SetTriggerValue(false);
 }
}

The dependency object that the event occured on is passed in as d and we just cast it to an instance of MyTrigger and then simply call SetTriggerValue with true or false.

Now we are ready to test our custom trigger. Switch to the XAML and add:

xmlns:m="using:app name">

so that we can use the classes defined in the application.

After adding this to the Page tag the rest of the XML is: 

<VisualStateManager.VisualStateGroups>
 <VisualStateGroup>
  <VisualState x:Name="Small">
   <VisualState.StateTriggers>
    <m:MyTrigger myCondition="60" />
   </VisualState.StateTriggers>
   <VisualState.Setters>
    <Setter Target="Button1.Content"
            Value="Triggered"/>
   </VisualState.Setters>
  </VisualState>
 </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<Button x:Name="Button1"
  Content="Not Triggered"
  HorizontalAlignment="Left"
  VerticalAlignment="Top"
  Margin="196,172,0,0"/>

If you run the program with a value of MyCondition of 50 or less you will see the button's label as "Not Triggered" and for values greater than 50 it will say "Triggered".

Yes, it really is this simple. 

The complete class is:

namespace App10
{
 public class MyTrigger : StateTriggerBase
 {
  public int myCondition
  {
   get { return
          (int) GetValue(MyConditionProperty); }
   set { SetValue(MyConditionProperty, value); }
  }

 public static readonly DependencyProperty
  MyConditionProperty=DependencyProperty.Register(
      "myCondition",
      typeof(int),
      typeof(MyTrigger),
     new PropertyMetadata(true, OnMyConditionChanged));

 private static void OnMyConditionChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
 {
  MyTrigger obj = (MyTrigger)d;
   if ((int)e.NewValue > 50)
   {
    obj.SetTriggerValue(true);
   }else{
    obj.SetTriggerValue(false);
   }
  }
 }
}

  

This particular Trigger is really only suitable for testing if the device has a set characteristic like a wide screen, which isn't going to change after the program has started running. For characteristics like orientation that can change while the program is running, you need to use the OnChanged event for the quality - orientation - being monitored. 

Where Next - Views

Although the new ViewStateManager facilities are very nice they aren't really powerful enough to deal with big changes to layout. You could use a trigger with, say, the new relative layout to position things, but this isn't easy.

When it comes to big changes you really need to design a layout for each type of screen and this is where the new Views facility comes into the picture - see the next article for more details. 

 icon

 

 

Related Articles

Getting started with C# Metro apps

Building and using C++ WinRT components

  

 

To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, FacebookGoogle+ or Linkedin,  or sign up for our weekly newsletter.

 

 

Banner


Deep C# - Casting the Escape from Strong Typing

Casting is one of the most confusing aspects of any modern language and it often makes beginners think hard. But if you know why you are doing it, then the how makes a lot more sense. We have encounte [ ... ]



Deep C# - Interface

Interfaces - what are they for? Not quite inheritance yet they seem to fit the same purpose. Find out in this extract from my new book, Deep C#: Dive Into Modern C#.


Other Articles

 

espbook

 

Comments




or email your comment to: comments@i-programmer.info

<ASIN:0321658701>

<ASIN:0321877586>

<ASIN:0672337266>



Last Updated ( Thursday, 09 April 2015 )