When the release candidate of Visual Studio 2013 came available, so did the Behaviors SDK. The Behaviors SDK is somewhat similar to the Expression Blend SDK you might have used before when using Behaviors and Actions. Along with the SDK come a couple of actions and behaviors you can use in your Windows Store applications right away.
What are they?
Both behaviors and actions are small pieces of code that can be reused throughout your projects. In the case of the new Behaviors SDK the only thing you need to do is implement an interface. A behavior adds some behavior to an element in your application. A behavior has a method that is invoked when the behavior is attached to a Dependency Object. It also has a method that is invoked when it is detached. An action contains only one method that is invoked when a certain condition is met. This condition can be a event that is raised, or a state of data or well pretty much everything.
Those of you who are used to working with behaviors and actions on other platforms might miss the triggers. Triggers where used to work together with actions, and presented the reason for an action to be executed. In the new Behaviors SDK triggers are no longer there. They are replaced by behaviors.
What’s in the SDK?
The Behaviors SDK consists of two parts. One (Microsoft.Xaml.Interactivity) contains the tools you need to create your own behaviors and actions(more about this is a sec). The other (Microsoft.Xaml.Interactions) contains a few of the most commonly used behaviors and actions(which are build with the interfaces from the first part b.t.w.). Not everything you might be used to working with from other platforms is included in de SDK, but I’m pretty sure these will be available through open source channels.
Let’s just go over the actions and behaviors included in de SDK.
Actions:
- CallMethodAction : An action that calls a method on a specified object when invoked.
- ChangePropertyAction : An action that will change a specified property to a specified value when invoked.
- GoToStateAction : An action that will transition a FrameworkElement to a specified VisualState when executed.
- InvokeCommandAction : Executes a specified ICommand when invoked.
- NavigateToPageAction : An action that switches the current visual to the specified Page.
- ControlStoryboardAction : An action that will change the state of the specified Storyboard when executed.
- PlaySoundAction : An action that will play a sound to completion.
Behaviors:
- DataTriggerBehavior : A behavior that performs actions when the bound data meets a specified condition.
- EventTriggerBehavior : A behavior that listens for a specified event on its source and executes its actions when that event is fired.
- IncrementalUpdateBehavior : A behavior that allows incremental updating of ListView and GridView contents to support faster updating. By attaching this behavior to elements in the ItemTemplate used by these views, some of the updates can be deferred until there is render time available, resulting in a smoother experience.
The other part contains two interfaces you need when building your own: IAction and IBehavior. There are some attributes and helper classes you can use too.
How do you build your own actions and behaviors? The short version: create a class that inherits from DependencyObject and implement the IAction interface or the IBehavior interface. Now, lets have a look a the long version…
Build your own Behavior
As I said earlier, you need to do is inherit from DependencyObject and implement the IBehavior interface. The code below shows the basic empty implementation of the interface. It might look familiar if you have build behaviors before. The Attach method is call when then the underlying object is initialized. At this point you need to add the new behavior to the associated object. It also is a good moment to set the AssociatedObject property to keep track of the associated object.
The Detach method is called when the behavior is removed from the underlying object. This would be the perfect opportunity to remove some event handlers and things like that.
public class SelectAllOnFocusBehavior : DependencyObject, IBehavior { public void Attach(DependencyObject associatedObject) { throw new NotImplementedException(); } public void Detach() { throw new NotImplementedException(); } public DependencyObject AssociatedObject { get; private set; } }
Lets walk through a simple implementation of a behavior. This behavior can be placed on a TextBox and will select it’s contents when the textbox gets focus. First have a look at the Attach method defined on line 6. In this method the associated object is stored in the AssociatedObject property. Next, the associated object is converted to a TextBox and, if it’s not null, the GotFocus event is being handled.
The handling of the GotFocus event is pretty simple in this case. Again, the associated object is converted to a TextBox and the text of that TextBox is selected.
Always be a good citizen and clean up after yourself. And that’s just what the Detach method at line 21 is for. It converts the associated object to a TextBox and removes the GotFocus event handler.
The last thing I would like to mention is the attribute on line 1. The TypeConstraint attribute limits the behavior to only be placed on a specified type, a TextBox in this case.
[TypeConstraint(typeof (TextBox))] public class SelectAllOnFocusBehavior : DependencyObject, IBehavior { public void Attach(DependencyObject associatedObject) { this.AssociatedObject = associatedObject; TextBox tb = this.AssociatedObject as TextBox; if (tb != null) { tb.GotFocus += tb_GotFocus; } } private void tb_GotFocus(object sender, RoutedEventArgs e) { TextBox tb = this.AssociatedObject as TextBox; tb.SelectAll(); } public void Detach() { TextBox tb = this.AssociatedObject as TextBox; if (tb != null) { tb.GotFocus -= tb_GotFocus; } } public DependencyObject AssociatedObject { get; private set; } }
Build your own action
An action needs to inherit from DependecyObject also, and it has to implement the IAction interface to make in an action. The IAction interface has only one method that needs to be implemented, Execute.
public class ShowFlyoutAction : DependencyObject,IAction { public object Execute(object sender, object parameter) { throw new NotImplementedException(); } }
Lets have a look at a real action. When using an AttachedFlyout you’ll have to use some code in your code behind file to show the flyout… Or you could us an action to do this in a way it can be reused. The code that you would use in your code behind is pretty much that same as the code that goes into the Execute method of the Action.
In this case the sender is converted to a FrameworkElement. And if it’s not null the ShowAttachedFlyout method is called, with the FrameworkElement passed as a parameter.
You might want to select the default event that triggers the Action. By default an Action is used in combination with the EventTriggerBehavior. The default event is “Clicked”. To change this you can use the DefaultEvent attribute on your action. In this case the default event is set to Tapped.
[DefaultEvent(typeof(FrameworkElement),"Tapped")] public class ShowFlyoutAction : DependencyObject,IAction { public object Execute(object sender, object parameter) { var element = sender as FrameworkElement; if (element != null) { Flyout.ShowAttachedFlyout(element); } return sender; } }
Anything else?
Well… I wouldn’t include a section like this if there wasn’t something else to talk about. There are two more helpful classes inside the Behaviors SDK.
The first is the VisualStateUtilities class. This static class can help you when working with visual states. It contains a couple of methods. GoToState and GetVisualStateGroups perform almost the same task as the similar methods on the VisualStateManager class. They use the VisualStateManager under the hood, but perform some extra checks too.
The FindNearestStatefulControl method walks up the visual tree and looks for any controls with visual state groups defined. It takes a FrameworkElement as a parameter as a starting point of the search. It returns the control with visual state groups, null if there isn’t any.
The second and last thing I would like to talk about is the CustomPropertyValueEditor attribute. With this attribute you define what property value editor must be used for a property of your action or behavior. The attribute takes only one parameter, a CustomPropertyValueEditor enum value. This enum contains four values: ElementBinding, PropertyBinding, StateName and Storyboard.
- ElementBinding : Shows the Element picker and lets you pick an element from the designer.
- PropertyBinding : Shows the Property picker and lets you pick an element and choose a property of that to bind to.
- StateName : Shows a dropdown list containing the Visual States of a file and lets you pick one.
- Storyboard : Shows a dropdown list containing the available storyboards and lets you pick one of those.
Wrap up
I am very happy behaviors and actions are available in Windows Store apps. I was missing these very much.
If you have written some behaviors or actions, for Windows Store apps or any other platform and you would like to share them with the world, you can use my new site for just that: http://blendbehaviors.net. This site lets you search behaviors and actions and submit your own.