Visual State Manager or rather Behavior ? (part 2)

In part 1 I set up the service and the WP7-application. The WP7-application will poll the service regularly for asking the distance to the closest friend. Let's now finish the WP7-app so we can show the distance by a little indicator. When closer than 2 (km? miles ? light-years ? You choose) the indicator will show green, less then 5 will be orange, and all the rest is red. Let's first create an indicator using Visual State Manager. In VSM we will define different states. In code we define the state our control is in, and in XAML we define how a state should look like.

Let's create our control:

   1:  [TemplatePart(Name="Core",Type=typeof(FrameworkElement))]
   2:  [TemplateVisualState(Name="Far",GroupName="DistanceStates")]
   3:  [TemplateVisualState(Name = "Close", GroupName = "DistanceStates")]
   4:  [TemplateVisualState(Name = "VeryClose", GroupName = "DistanceStates")]
   5:  public class DistanceIndicator: Button
   6:  {
   7:      Ellipse corePart;
   8:   
   9:      private Ellipse CorePart 
  10:      {
  11:          get { return corePart; }
  12:          set { corePart = value; }
  13:      }
  14:   
  15:      public override void OnApplyTemplate()
  16:      {
  17:          base.OnApplyTemplate();
  18:   
  19:          CorePart = (Ellipse) GetTemplateChild("Core");
  20:          VisualStateManager.GoToState(this, "Far", true);
  21:          DistanceReader.DistanceChanged += 
  22:              new EventHandler<DistanceEventArgs>(DistanceReader_DistanceChanged);
  23:      }
  24:   
  25:      void DistanceReader_DistanceChanged(object sender, DistanceEventArgs e)
  26:      {
  27:          if (e.Distance>5)
  28:          {
  29:              VisualStateManager.GoToState(this,"Far",true);
  30:          }
  31:          else if (e.Distance > 2)
  32:          {
  33:              VisualStateManager.GoToState(this,"Close",true);
  34:          }
  35:          else 
  36:          {
  37:              VisualStateManager.GoToState(this, "VeryClose", true);
  38:          }
  39:      }         
  40:  }

The code-attributes already shows you the different states my Indicator can have : Far, Close and VeryClose (OutOfInspirationException occurred). I add the controltemplate to App.xaml, describing how my three states should look like :

   1:  <ControlTemplate x:Key="u2uCtrl" TargetType="my:DistanceIndicator">
   2:      <Ellipse x:Name="ellipse" Height="{TemplateBinding Height}" Fill="Yellow">
   3:          <VisualStateManager.VisualStateGroups>
   4:              <VisualStateGroup x:Name="DistanceStates">
   5:                  <VisualState x:Name="Close">
   6:                      <Storyboard>
   7:                          <ColorAnimation Duration="0" To="Orange" 
   8:                                          Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
   9:                                          Storyboard.TargetName="ellipse" d:IsOptimized="True"/>
  10:                      </Storyboard>
  11:                  </VisualState>
  12:                  <VisualState x:Name="VeryClose">
  13:                      <Storyboard>
  14:                          <ColorAnimation Duration="0" To="Green" 
  15:                                          Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
  16:                                          Storyboard.TargetName="ellipse" d:IsOptimized="True"/>
  17:                      </Storyboard>
  18:                  </VisualState>
  19:                  <VisualState x:Name="Far">
  20:                      <Storyboard>
  21:                          <ColorAnimation Duration="0" To="Red" 
  22:                                          Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
  23:                                          Storyboard.TargetName="ellipse" d:IsOptimized="True"/>
  24:                      </Storyboard>
  25:                  </VisualState>
  26:              </VisualStateGroup>
  27:          </VisualStateManager.VisualStateGroups>
  28:      </Ellipse>
  29:  </ControlTemplate>

I cheated, of course: I used blend for creating this template. Nevertheless, I add my control to my MainPage:

<my:DistanceIndicator Content="" x:Name="distanceIndicator1" Template="{StaticResource u2uCtrl}" />
That's it. Open the WPF-application, change the slider. Run the WP7-application and there you go. Play with the slider, and the WP7-app responds visually (after some time). Nice stuff, but it get's nicer with Behavior. That's for part 3.