The objective of this article series is to give a quick overview of Behaviors, Triggers and Actions in Silverlight and WPF.  Together, they enable a great deal of design time interactivity for your UI. They also make possible re-use and re-distribution of interaction logic. This is the second article in the series, and I’ll explain about Triggers and Actions. Also, we’ll explore how to create custom triggers.

Note: You need Expression Blend 4.0

The completed source code for this exercise is available

 

Triggers and Actions – Scratching the Surface

A Trigger can invoke a set of Actions, when it is fired. For example, you can nest few actions (like PropertyChangeAction to change a property of an element) in an EventTrigger, so that those actions will get executed when a specific Event occurs. You can attach more than one trigger to an element.

If you have some WPF background, you may quickly remember the DataTriggers, MultiDataTriggers etc.

There are various Triggers and Actions that comes ‘out of the box’, residing in System.Windows.Interactivity and Microsoft.Expression.Interactions 

  • Triggers – EventTrigger, TimerTrigger, StoryBoardCompletedTrigger, KeyTrigger etc.
  • Actions - ChangePropertyAction, ControlStoryBoardAction, PlaySoundAction etc.

Let us start playing with some of the existing triggers and actions.

1.  Set The Stage - Create a new Silverlight Application Project in Blend (as explained in my previous post). You’ll see the design surface of MainPage.xaml by default. This time, select the Ellipse tool from Blend toolbar, to draw a ball to the design surface. Give some nice color as well :)

image

Also, at this point, click View->Active Document View->Split View – So that you can view the Xaml along with the designer.

2. Attach a Trigger and Action to an object – Go to the Assets pane in Blend, and click the Behaviors link. Drag the ChangePropertyAction to the ellipse you added, and have a look at the XAML. You’ll find that Blend automatically added an EventTrigger for you with MouseLeftButtonDown as the default event, and sandwiched your ChangePropertyAction inside the same.

image

 

Select the ChangePropertyAction in the Xaml Editor or in the Object and Timelines window. Have a look at the properties Window in blend, to see the properties of your Trigger and Action (See the image below). By default the trigger will be fired for the MouseLeftButtonDown event of our ball. Also, you may note that presently we havn’t specified any parameters for the ChangePropertyAction.

image

3.  Modifying ChangePropertyAction image

Now let us squeeze our ellipse a bit by changing the Width property of our Ellipse - when the MouseLeftButtonDown happens. For this, go to the properties window, and

 

1. Change ‘PropertyName’ parameter of our ChangePropertyAction to ‘Width’.

2. Set the the value to 200 so that Width will increase to 200 when the Action is invoked

3. In the Animation Properties of ChangePropertyAction, set the duration to 4 seconds, and change the Ease property to Elastic Out.

We are done. Run the application, by pressing F5 and move click over the Ellipse. And you’ll see a bit of fun.

Play around with this a bit, to understand how the Triggers and Actions work together. And once you are back, scroll down to read further – about creating our very own Triggers and Actions

 

Creating a Custom Trigger

Time to go under the skin.  Then, we’ll replace the ‘EventTrigger’ we used in our above example with the custom trigger we are creating, to stretch the ball!!.

First, let us create a minimal custom trigger – named KeyDownTrigger, that’ll be fired each time when a key is pressed. Let us continue from where we left our above project.

Step 1 – Create a Trigger: In Blend, right click your project in the Projects pane, and click ‘Add New Item’, to bring up the New Item dialog box. Select ‘Trigger’ from there, give the name ‘KeyDownTrigger’ and click OK.

image

Step 2 – Add some meat. Have a look at the New trigger class that got added to your project. You’ll find that our Trigger class is inherited from TriggerBase<T> in System.Windows.Interactivity. Also, have a look at the override methods, OnAttached and OnDetaching (and the comments below them). Let us add some meat to the code you already see there. Modify the code to this.

Tip: If you have Visual Studio 2010 Beta installed, you can right click on a file in Blend 4.0 project explorer, and click ‘Edit in Visual Studio’ at any point of time, if you prefer writing code in VS rather than in Blend.

public class KeyDownTrigger : TriggerBase<FrameworkElement>
	{
		protected override void OnAttached()
		{
	         base.OnAttached();
	       // Insert code that you want to run when the Trigger is attached to an object.
             this.AssociatedObject.Loaded += (sender, args) =>
            {
                Application.Current.RootVisual.KeyDown +=
                    new KeyEventHandler(Visual_KeyDown);
            };
		}

		protected override void OnDetaching()
		{
			base.OnDetaching();
			// Insert code that you would want run when the Trigger
			//is removed from an object.
            Application.Current.RootVisual.KeyDown -= 
				new KeyEventHandler(Visual_KeyDown);
        }

        //A property for the trigger so that users can specify keys
        //as comma separated values
        public string Keys { get; set; }

        //Invoke the actions in this trigger, if a key is in the list
        void Visual_KeyDown(object sender, KeyEventArgs args)
        {
            var key = Enum.GetName(typeof(Key), args.Key);

            if (Keys.Split(',').Contains(key))
                InvokeActions(key);
        }
    }

The code is self explanatory, but here is basically what we are doing there. When the Associated object is loaded, we hook up to the KeyDown event of the Root visual element. And when KeyDown is fired, we Invoke the Actions inside this trigger, if the key is entered by the user.

Step 3 – Associate the KeyDownTrigger to our Ball.

In Blend, click Project->Build Project menu. Now, go back to our MainPage.xaml where you have your ball. As we did earlier, Select the ChangePropertyAction in the Xaml Editor or in the Object and Timelines window, to bring up the Properties Window - as we did earlier. In the Properties window, Click the ‘New’ button against the TriggerType, in the Trigger Pane (see the image). In the resultant dialog box, select the ‘KeyDownTrigger’ we recently added, and click OK.

image

 

Now, you’ll see that the ‘EventTrigger’ we had there earlier, got replaced with the ‘KeyDownTrigger’. Note that the ‘Keys’ property we added to our Trigger class is visible in the Blend UI - so that some one who may use our trigger can enter the values there to specify what all keys should invoke the actions inside the trigger. Just enter few key names with out spaces (let us say A,B,C) to the Keys field.

image

 

Step 4 – Salvation

Cool, we are done. Press F5 and run your project. Click on the surface to bring focus, and press A,B or C to see the ball getting stretched. Woot!! We just created and implemented a minimal trigger.

Shout it
Read more >>

The objective of this article series is to give a quick overview of Behaviors, Triggers and Actions in Silverlight and WPF. Together, they enable a great deal of design time interactivity for your UI. They also make possible re-use and re-distribution of interaction logic. This is the first article in the series, and I’ll explain about Behaviors and creating custom behaviors.

Note: You need Expression Blend 4.0

Note: Why this post? After publishing my Silverlight and WPF interaction frameworks, Silverlight Experimental Hacks (Slex)  and WPF Experimental Hacks (Wex), I got a number of requests from the community to write few simple posts on these topics, introducing the basic concepts. So here we go.

Behaviors – Scratching the Surface

A behavior is something you attach to an element, modifying the way how the element should present itself, or how the element should respond to user interactions. First, Let us add an existing behavior to an object to see how behaviors work. Later we’ll create a custom behavior and may use the same from Blend.

Step 1. Let us start with a simple Silverlight application. Fire up Expression Blend 4.0 beta, and click File->New to select a Silverlight 4.0 application, and click OK.

image

Step 2. Once you have the project created, just add a rectangle to your MainPage.xaml canvas, and give it a nice back ground color using the color picker (I gave blue:)). Also, at this point, click View->Active Document View->Split View – So that you can view the Xaml along with the designer. You may also press F5 and run the project if you want, and make sure you can’t drag the rectangle around as of now ;).

image

Step 3. Now, our objective is to attach a dragging behavior to our rectangle, so that it can be dragged around by the user in the screen. For this, we’ll attach the MouseDragElementBehaviour to our rectangle. To do this, go to the Assets tab in Blend (See the arrow below), and Click the Behaviors label. Now, from the right pane of the Assets tab, drag and drop MouseDragElementBehaviour to your rectangle. Press F5 and run the project, and you see that you’ll be able to drag your element any where.

image

Step 4. Let us take a step back here, and have a look at the XAML. You’ll see the MouseDragElementBehaviour added to the Behaviors attached property of our dumb little rectangle.

image

Behind the scenes

The System.Windows.Interactivity infrastructure (initially introduced in Blend 3) simplifies the creation of Behaviors, triggers and actions.

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:il="clr-namespace:Microsoft.Expression.Interactivity.Layout;assembly=Microsoft.Expression.Interactions"

The System.Windows.Interactivity namespace has multiple classes to inherit from and to create your own Behavours, triggers and actions. The WPF and Silverlight versions are present at C:\Program Files\Microsoft SDKs\Expression\YourBlendVersion\Interactivity\Libraries. In the same folder, you’ll also find the Microsoft.ExpressionBlend.Interactions.dll which hosts various concrete behaviours and triggers, like the MouseDragElementBehaviour we just applied.

If you have a look at the MouseDragElementBehavior using Reflector, you’ll find that MouseDragElementBehaviour is inherited from the Behaviour<T> abstract class in System.Windows.Interactivity.

image

Creating your own Behaviors

So, let us create a custom behavior. 

Step 1 – Create a Behavior. In Blend, right click your project in the Projects pane, and click ‘Add New Item’, to bring up the New Item dialog box. Select Behavior from there, give a nice name and click OK.

image

Step 2 – See what is inside. Have a look at the New behavior class that got added to your project. You’ll find that our Behavior class is inherited from Behavior<T> in System.Windows.Interactivity as discussed earlier. Also, have a look at the override methods, OnAttached and OnDetaching (and the comments below them).

image

Step 3 – Add some meat. And what we should do in the Behavior? Let us tilt the object a bit, when the mouse moves over an object with this Behavior applied. Just modify OnAttached to have the following code. The AssociatedObject property of the Behavior will provide the current object context, to which this behavior is applied. Let us hook the MouseEnter and MouseLeave events, so that we’ll apply a simple projection to the object when the mouse moves over, and reset the project when the mouse leaves the object.

image

Step 4 – Rebuild. Now, click Project->Build Project in Expression Blend menu. And goto the Assets window again and click Behaviors to view MyBehavior there. Just drag and drop the behavior to your object. See that the new behavior is added to our Rectangle in Xaml as well.

image

 

Step 5 – Run. You are done. Press F5 and run your project, and see that when you move your mouse over the rectangle to start the dragging, the rectangle is getting a bit tilted.

 

Continue reading - Part II - Behaviors, Triggers and Actions in Silverlight And WPF Made Simple – Triggers

Shout it
Read more >>

Some time back, I posted about the Silverlight Extensibility hacks Preview 2.0. I did a quick port of the code base to WPF under the name WEX or WPF Extensibility hacks, and now you have the goodness in .NET 3.5 + VS 2008

image

Just want to have a quick word on what is available. Here are a couple of points about Wex. Wex is built on top of System.Windows.Interactivity infrastructure.

  • Wex allows you to define multiple conditions for invoking triggers (like you can specify a KeyDown event trigger should be fired only if ‘A’ is pressed)
  • You can specify multiple conditions for invoking each action in a trigger
  • Wex introduces few more Triggers and Actions that you’ll see soon.

As of now, Wex Preview 1 Provides the following Triggers

  • EventTrigger – Will be fired when an event is raised. Can listen to events of Elements, or events from your view model
  • ReactiveTrigger – Can ‘import’ an Observable that you may ‘export’ using MEF. Useful to define and use custom events using System.Reactive.

And the following actions

  • InvokeMethodAction – Invoke a method directly in the View model or for a target element, supports passing parameters via Xaml
  • InvokeCommandAction – Invoke an ICommand in the view model
  • StoryBoardAction – Start, Stop, Pause, Resume, or Reverse story boards
  • PropertyAction – Sets a property value (very crude as of now)

Event Trigger

You can hook up the event trigger against your view model, or against an element. For example, assume you want to invoke a command in your view model based on various conditions – let us say, when the user presses the key ‘A’, and if and only if a check box is checked. Here we go

image

Reactive Trigger

The concept of reactive trigger is based on the System.Reactive (LINQ to Events) framework and Managed Extensibility Framework. Basically, you can create an event definition, and import that as an event for a control.

Your exported event definition should match the signature Func<object,IObservable<EventResult>>. You can use the ObservableExport attribute in Wex.Lib to mark your trigger as an exportable part. Also, the name you provide to the ExportName attribute will be later used in Xaml to ‘import’ this trigger.

image

Step 2 – In your application startup, call Compose method in WexPartComposer, and pass your catalogs

In this case I’m simply passing and assembly catalog with the current assembly, because I’ve my trigger as part of my host app. And I’ve this line in the App.xaml.cs constructor.

image

Step 3 – Just use the trigger in your Xaml

Here we go, you can import the exported trigger, and this will get fired when ever a key is pressed.

image

You might have guessed this, but you can create very customized event definitions using System.Reactive. For example, here is how to create an event definition if you want the trigger to fire only when the arrow keys are pressed.

image 

You can read this article on Reactive Extensions, to understand more on this

Actions in Wex

You might have already noticed in the above examples, how to use the actions like InvokeCommandAction, StoryBoardAction etc. What is interesting is, Wex allows you to fire actions based on conditions (See the EventTrigger example where we are specifying the InvokingConditions for the actions.

I specifically want to comment on the InvokeMethodAction in Slex, that allows you to Invoke a method in view model directly. Here we go. Assume that you have an Add method in your view model, like this.

image

Now, this is how to invoke the add method, passing some parameters. Here, we pass the text in txt1 and txt2 as parameters.

image 

A Quick Overview

Have a sneak peak at the actual implementation of Wex. If you examine the Trigger hierarchy, you’ll find that we’ve a WexTrigger abstract base class, from where other triggers are getting inherited.

  • WexTrigger - The base class for all Wex framework triggers
  • EventBasedTrigger - A base class for inheriting event based triggers
  • ObserverTrigger - An abstract class for creating triggers based on an Observable (System.Reactive)

WexTrigger directly inherits from System.Windows.Interactivity.TriggerBase<DependencyObject>. I’m not going to explain the System.Windows.Interactivity infrastructure and how each trigger is implemented, but you can definitely go through the source code and find the same yourself. Probably I’ll explain implementation details in future posts.

 

Triggers

      Actions

Now, let us have a quick look at the Actions involved. Have a look at the actions in the framework. WexTriggerAction is inherited from System.Windows.Interactivity.TriggerAction<FrameworkElement>, and from there on, you can go and explore as of now if you’ld like to :)

Conclusion

As I mentioned, Wex is a quick port of Slex, and seriously, there are lot of areas I still need to re-write to leverage what is already available in WPF (Especially on dependency property hooking and all). How ever, I thought it might be good if I bring out a first cut, so that you can also hack around with me, and leverage some of these concepts in your own apps.

And you may hit few bugs with this Preview, fix it yourself or wait for the Preview 2. But please give feedback!!

Enjoy Coding!!

Shout it
Read more >>

Silverlight Powered Wearable Locket

Can I have a call with all the Project Natal, Win Mob and Silverlight guys to tell them, “Guys, let us get this thing out by next month”?

 

image

Shout it
Read more >>

In my last post on Dependency Properties (Read here), I explained how to  listen for dependency property change notification of a UI Element. image

Here is a more ‘refined’ extension method - so that you can listen to Property change notifications of a source - by creating and registering a ‘listener’ dependency property in your class ('owner') and setting up a binding with the ‘source’ object. Remember that starting from Silverlight 4.0, you can even have dependency objects as the source.

This is useful when you create your own Silverlight Behaviors, triggers or actions. For example, you may want to listen to the property change notification of an element - to Invoke your trigger when the property value of the ‘source’ changes.

 

    public static class DependencyPropertyHelper 
    {
        /// <summary>
        /// Listen for change of a property of the source, 
        /// and callback the same to the context via the callback
        /// </summary>

        public static System.Windows.DependencyProperty RegisterForNotification
            (this DependencyObject owner, object source,
            string propertyPath, PropertyChangedCallback callback)
        {

            return RegisterForNotification(owner, source, propertyPath, callback, false);

        }

        /// <summary>
        /// Listen for change of a property of the source, 
        /// and callback the same to the context via the callback.
        /// Creates a two way binding if you specify 'twoway' to true
        /// </summary>
        /// <param name="propertyPath"></param>
        /// <param name="element"></param>
        public static System.Windows.DependencyProperty RegisterForNotification
            (this DependencyObject owner, object source,
            string propertyPath, PropertyChangedCallback callback, bool twoWay)
        {

            //Bind to a depedency property
            Binding b = new Binding(propertyPath) { Source = source, Mode = BindingMode.OneWay };
            if (twoWay) b.Mode = BindingMode.TwoWay;

            var prop = System.Windows.DependencyProperty.RegisterAttached(
                "Listener" + propertyPath + DateTime.Now.Ticks,
                typeof(object),
                owner.GetType(),
                new System.Windows.PropertyMetadata(callback));

            BindingOperations.SetBinding(owner, prop, b);

            return prop;

        }
    }

And now, from your 'owner' class (say, from your trigger or behavior class), you can set up a binding to a source like this.

//Register for notification some where
this.RegisterForNotification
    (Source, this.Property, OnPropertyValueChanged);

//...

/// Callback invoked when the property changes
private void OnListenAttachedPropertyChanged(DependencyObject dependencyObject,
      DependencyPropertyChangedEventArgs eventArgs)
   {
           //Do stuff here
   }

If you want to update the source property value to which you are binding, you might want specify that the twoway parameter is true when invoking RegisterForNotification - and keep the dependency property created for updating the value, later like

targetDP =this.RegisterForNotification
              (Target, this.Property, OnPropertyValueChanged, true);


//Later, set the value some where
 SetValue(targetDP, Value);

 

You may find the DependencyPropertyHelper class and a related PropertyChangedTrigger implementation here in Slex project - http://slex.codeplex.com

Shout it
Read more >>

top