h3mm3's blog

Stories from behind the keyboard

  • RSS
  • Twitter

If you want to encapsulate some behavior into a class in order to reuse it by writing simple XAML code, you can inherit from a bunch of classes such as Behavor, TriggerActions,  and TargetedTriggerAction. For instance, in the following code I created a MagnifyTriggerAction, which provides an object the capability to be scaled when an event occours.

public class MagnifyTriggerAction:TriggerAction<frameworkelement>
{
 public double Factor { get; set; }
 protected override void Invoke(object parameter)
 {
  var zoom = new ScaleTransform
   {
     ScaleX = Factor,
     ScaleY = Factor,
     CenterX = _centerX,
     CenterY = _centerY
   };
  AssociatedObject.RenderTransform = zoom;
 }

 protected double _centerX, _centerY;
 protected override void OnAttached()
 {
   base.OnAttached();

   _centerX = .5 * AssociatedObject.Width;
   _centerY = .5 * AssociatedObject.Height;
 }
}

The following code shows a somewhat more complex TriggerAction, inherited from the previous class. This class inherits from its base class the behavior of attaching a ScaleTransform to the AssociatedObject and has the new capability of altering the Opacity of the AssociatedObject based on the value of two properties (for the sake of simplicity, here I haven't implemented them as DependencyProperties but of course you can do it...).

public class MagnifyAndFocus:MagnifyTriggerAction
{
 public double OpacityAfterTrigger { get; set; }
 public double OpacityBeforeTrigger { get; set; }

 protected override void Invoke(object parameter)
 {
  base.Invoke(parameter);
  if (OpacityAfterTrigger!=0)
   AssociatedObject.Opacity = OpacityAfterTrigger;
 }
 protected override void OnAttached()
 {
  base.OnAttached();
  if (OpacityBeforeTrigger!=0)
   AssociatedObject.Opacity = OpacityBeforeTrigger;
 }
}

Using these TriggerActions is quite simple. For instance, first of all I declared the System.Windows.Interactivity namespace and assembly (and thanked Blend 3 for it).
<UserControl
 ...
 xmlns:b="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
 ...
>

Then, in the XAML, I attached the TriggerAction to an object (here an hypotetical SomeElement type) using an Interaction.Triggers element that wraps two EventTriggers. When the first TriggerAction is attached to the object (by the first EventTrigger), it sets the Opacity of the object to the OpacityBeforeTrigger value (in this case, it's 0.5) - see the OnAttached(..) implementation. The first trigger will fire on every MouseEnter event and start the Invoke(..) method of the MagnifyAndFocus TriggerAction, wich, in sort, zooms the object a little bit (120%) and restores its Opacity to 1.0. The second trigger will reset scaling and opacity, on every MouseLeave event.

<SomeElement Rows="3" Columns="3" Width="50" Height="50">
 <b:Interaction.Triggers>
  <b:EventTrigger EventName="MouseEnter">
   <my:MagnifyAndFocus 
    Factor="1.2" 
    OpacityAfterTrigger="1.0"
    OpacityBeforeTrigger="0.5"/>
   </b:EventTrigger>
  <b:EventTrigger EventName="MouseLeave">
 <my:MagnifyAndFocus 
   Factor="1.0" 
   OpacityAfterTrigger="0.5"
  />
  </b:EventTrigger>
 </b:Interaction.Triggers>
</SomeElement>

No comments: