When Visual Studio 2012 was released, it supported a new way of building apps – Windows Store apps using the Windows Runtime. These apps could be built in XAML, of course. But, unlike previous Microsoft developer tooling, Expression Blend was not shipped separately; it was moved out of the Expression Suite (which was discontinued), and bundled as part of Visual Studio – forevermore.
This meant all developers completing developer tasks could use Visual Studio with comprehensive coding features. Moreover, all developers completing design tasks could use Blend for Visual Studio with comprehensive animation and styling features. It was a brilliant union. Today, still, a Visual Studio installation includes Blend by default. Developers have the best of both worlds.
Aside: this article does not talk about custom behaviors. It’s not that custom behaviors are too complex, it’s that there’s too much to say about the built-in behaviors first. I’ll try to follow-up with a custom behaviors article. In the meantime, enjoy.
The mind-meld starts now…
In the beginning
Born as Sparkle (codename) in 2006, developers and designers acquainted with Blend had a genuine love affair with the tool. Its ability to visualize styles and simplify animations was intoxicating power. But, paramount, its ability to encapsulate complex code in Interaction Behaviors meant developers could build apps with reusable code and very little net-new logic – like building with Legos, only more awesome. (if that’s possible)
To be fair, most developers avoided Blend. First, developers thought it was only for designers. Of course, this was not correct because Blend was for design tasks, not (just) designers. Second, developers wore a t-shirt reading “I am no good at UI”. It wasn’t a lie, most developers weren’t/aren’t that great at UI, but it was typically just an trite excuse to spend more time on Linq syntax than the SolidColorBrush. Third, Blend was the dark theme. To be honest, this was almost unforgiveable. The dark theme sucks. Totally. Do you like the dark theme? I don’t care, don’t send me an email telling me all about it. It’s just not my thing.
Dead on arrival
So, when Blend for Visual Studio 2012 didn’t ship with Interaction Behaviors, developers flip their lids in melancholy consternation and loud objections. Why would Microsoft wantonly abandon Behaviors? This key feature accelerated development and promoted improved code reuse. With Blend for Visual Studio 2012, Behaviors were tossed away like old socks. Or were they? The rest of the story eventually came to light. The Windows Runtime and its inherent parity with Native code (and other things) made the previous Behaviors implementation unusable; a new engine was in development, but missed the Blend for Visual Studio 2012 ship date.
The return of the king
For a year, developers lumbered through app development without their precious Behaviors. Most continued to blog their disapproval, but as the facts emerged, MVPs and influencers around the community saw the new work peek out, participated in the feature’s direction and future, and eventually downloaded the confirming Blend for Visual Studio 2013 //Build preview with the Behavior SDK. That //Build presentation announced the re-introduction of Interaction Behaviors in Blend, and the SDK for custom Behaviors. There was a real nerd ovation, if you were there.
What is a behavior
So, have you ever seen the site IFTTT? It’s a pretty cool site called “If This Then That”; it listens for something to happen, then it does something else. For example, when I post a new article, I could use IFTTT to submit a tweet about it – but I don’t. Anyway, it listens for a new article and reacts with a tweet. That’s just like a Behavior in Blend. A Behavior listens for something to happen. It can listen for an event to be raised, or data to be changed, or some custom action you want to monitor – including being attached to a specific type of control. That’s a Behavior in Blend.
Aside: Developers can create custom Behaviors simply by implementing IBehavior (find the interface in the Behavior SDK that installs with Visual Studio). Different from previous Behavior implementations (i.e.: Visual Studio 2010), there is no concept of trigger. This capability is now part of IBehavior and the API is generally simplified.
Managed developers might want to sniff inside the built-in Behaviors with Reflector. Go for it. You might notice some reflection. Because of reflection, managed Behaviors can accomplish almost anything; in addition, this new implementation of Behaviors permits previous Behaviors to be ported with near-perfect parity of function.
Native Behaviors are a different story.
Native developers will enjoy Event-based Behaviors, but might notice there is a limit of ~12 supported events. These events have to be known in advanced for the Native implementation. At its heart, the reason is because Native code does not support any performance-reasonable type of reflection. This discrepancy means the Managed and Native SDK are in near-parity, not in perfect-parity. And, it is important to note, Windows Runtime apps do not support reference aliasing. This means you cannot reference both the Managed and the Native SDK. So, software architects, you might need to do some planning if you are wanting to mix XAML and DirectX in your Store App. You can’t cross the streams. There’s only one supported SDK at-a-time. Your Behaviors Library needs to be homogeneous.
What is an action
But a Behavior is only half the story. A Behavior is nothing without the resulting Action. For that reason, Blend has both Behaviors and Actions. The Behavior is responsible for listening for something, but also for invoking an Action. And, it doesn’t have to be just one Action either – a Behavior can invoke any number of Actions. Actions can do things like invoke a method, change a property, go to a Visual State, and anything you dream up.
Aside: Developers can create custom Actions simply by implementing IAction (find the interface in the Behavior SDK that installs with Visual Studio). You can include these in your project or reference them from a reusable project library.
I want to reiterate that last paragraph. Because Actions are custom operations, you can ask your star developers to create them, and tell your mediocre developer to use them. As a result, you can maintain the quality of your app code. You already create control libraries. You already create class libraries. Now you can create and maintain interaction libraries.
This, of course, also means that when you update an Action, all the controls leveraging the Action are updated. Someday (maybe), when Actions are part of the Visual Studio IDE, the ubiquity of Behavior encapsulation won’t be relegated to the good developers employing Blend. But for now, Blend is still for every Developer and there’s little excuse not to use them as a Best Practice.
Is this really development?
With Behaviors and Actions in Blend for Visual Studio 2013, you might be wondering “Is this really development?” And, of course it is. But, I see your point. Instead of unique, hand-coded event handlers for every user interaction, you are configuring your UI to react with robust, encapsulated code over and over. Of course, there is development to be done. But, there’s less thanks to Behaviors.
The Built-in Behaviors
Blend for Visual Studio 2013 ships with three Behaviors out-of-the-box. Having said that, it is an important reminder that you can create your own Behaviors by implementing IBehavior. However, what do these out-of-the-box Behaviors do? Let’s see.
The Event Trigger Behavior can be attached to any control in the XAML tree. It is configured to “listen” to one event that will be raised. The event it is listening for does not have to be raised by the same control to which the Behavior is attached. For this reason, the Behavior’s TargetObject property is available – so, you can attach the behavior to one object, but listen to another. For example, you can attach to the Page whilst listening to the View Models LoadCompleted event. At its heart, the Event Trigger Behavior is a simple event handler.
In the code above there are two properties to notice. The first is EventName. This correlates to an event in the Source Object – like Click on a button or LoadCompleted in your View Model. The SourceObject property is the next to notice. This indicates which object has the event and will raise it. What causes the event to raise does not matter to the Behavior. The Behavior simply waits for the event to be raised.
You might be impressed when noticing that Blend selects the most useful event first. For example, when you attach this Behavior to a Button the Click event is selected. How is Blend so smart? It’s because of the DefaultEventAttribute in the Microsoft.Xaml.Interactivity namespace. This communicates to the designer which event should be initially selected. This is important because you can use this custom attribute to decorate your own controls, giving an excellent design-time experience to developers.
The Data Trigger Behavior, like the Event Trigger Behavior, can be attached to any control in the XAML tree. The Behavior is bound to any INotifyPropertyChanged-enabled property in your View Model or elsewhere, including dependency properties on other controls. The Data Trigger Behavior could be called the “When-the-property-value-changes-then-do-something-behavior”, but that URL was already taken.
It is an important concept to understand that, like more than one event handler can be attached to a control, more than one behavior can be attached to a control. For example, if you are creating a scenario that when a slider’s value is below 50 it colors a rectangle green, and when it is above 50 it colors the rectangle red, this would require two Data Trigger Behaviors, each invoking a Change Property Action (which we will discuss later).
In the code above, you can see the rectangle has more than one behavior. One changes it to green when the Slider’s value property is LessThanOrEqual 50. The other changes it to red when the Slider’s value property is GreaterThan 50. Coordinating Behaviors gives the developer/designer a lot of power – but it should not be overlooked that it also adds complexity that requires an attentive mind.
The property most interesting with Data Trigger Behaviors is the ComparisonCondition property which represents the operator used to trigger the Behavior. There are the six common operators, while the left value is bound and the right value can be either bound or literally coded (as in the code snippet).
Multicasting a behavior?
Just when do multiple behaviors run? Well, just like handling any other event, a member is added to the event’s delegate list. Behaviors are attached to events in series, and in the order of their ordinal declaration in the XAML.
This is relevant when two Behaviors attach to the same event. In this case, the Behaviors will be invoked following our standard .Net multicasting heuristic. When multiple Behaviors attach to different events, the order of invocation is not predicable. As a result, your Behaviors should never-ever be constructed to rely on their order of execution. Having said all that, Managed Behaviors are 100% written in a Managed Language; they aren’t doing anything under-the-hood that you aren’t already familiar with. That is to say, .Net is .Net. They’re just event handlers.
The Incremental Update Behavior is unlike the other two Behaviors. The Incremental Update Behavior cannot be attached to any control in the XAML tree and isn’t compatible with any Actions. Instead, it is intended for controls inside the DataTemplate of ListViewBase controls, which in Windows Store Apps are the GridView and the ListView. What’s special about ListViewBase? CCC, that’s what. Keep reading.
Once the Incremental Update Behavior is attached to ItemTemplate children (like a TextBlock or DatePicker), it sets the opacity of those controls to zero – invisible. Controls with a zero opacity are not included by the renderer. With this Behavior, the developer can indicate in what order the controls in a template are rendered. This is particularly important in scenarios where the user is quickly panning large datasets. This creates a smoother experience.
In the code above, it’s the Phase property that’s really interesting. Setting the Phase indicates what order each control will be rendered. Understanding Phase is all there is to understanding the Incremental Update Behavior. So, let me explain.
When your DataTemplate is rendered, it attempts to render the whole thing. The problem is, complex templates take long to render – we’re talking milliseconds here. If the user is scrolling large datasets, he may only be viewing your record’s template for a split second – if there is insufficient time to render that template, the user will simply see black. This is a bad experience.
Of course, developers can handle the ContainerContentChanging event to manually stagger their content – setting control opacities to zero and easing them into the render cycle. The event is raised over and over, enumerated by a Phase property – which indicates the number of times the event has been raised. This lets template-specific placeholders appear first, and complex controls appear later. The render order is the responsibility of the developer – that will not change.
The IncrementalUpdateBehavior is a wrapped implementation of this strategy. The developer does not need to handle ContainerContentChanging; the behavior does. It manages render order for you, you simply indicate which loads first, second, and so on. Okay, yes, you could write your own; there’s no magic; but, use the Behavior.
Some take-away nuggets
The first phase is zero (0). Unassigned controls default to zero. Setting a parent to later phase than its children causes the children to render later. Setting more complex controls to earlier phases causes delays for later controls. The tick between phases is determined by the hardware’s ability to respond. When using this Behavior, disable Placeholders. Using this Behavior in every panned template is a best practice; if not, at least handle CCC.
Remember, a Behavior listens for the triggering event, but by itself, a Behavior is useless. That’s because a Behavior doesn’t do anything. In order to do something, a Behavior needs one or more Actions. There are several Actions built-into Blend. Let’s look at them.
The Call Method Action allows you to call a method. Yep, it’s that straight-forward. This Action was around in the previous WPF and Silverlight version of Behaviors, and it operates the same way. There are two things to know about this Action. The first is, it expects a method with zero parameters. The second is, if you want to call a method with arguments, the method’s arguments must match (object sender, object params). Make sense? If you are attaching to the Click event of a button (for example), your method must either have zero arguments or the alternate two argument signature. With the two-argument approach you can cast the resulting parameters into the appropriate types.
In the code above, notice TargetObject. In this case, I am binding it to the DataContext of the Button. Because I have set the ViewModel as the DataContext of the Page, it has inherited down the tree to the Button. The RefreshData method, which is in the ViewModel, is the resulting action of the Button’s Click event. Awesome.
By the way, The designer does not guide you to select your method. Instead, you just type it in literally. Get the spelling correct. It’s worth pointing out that the value of MethodName can be data bound, too; you can change the action based on a condition inside your ViewModel. Awesome.
An excellent Windows 8.1 application for this is the new SearchBox control. Since this does not support commanding, you can handle the various control events with an Event Trigger Behavior mixed with a Call Method Action that interacts directly with your View Model, maintaining UI separation.
C# Equivalent: That CallMethodAction XAML (above) is the equivalent to this:
Remember, with great complexity comes great maintenance cost. So be careful.
The Change Property Action is slick. Like the Call Method Action invokes a method isn’t net-new. It changes the value of a property to some specified new value. Let me show you how easy it can be to use this action. Look at this XAML.
A great use for this action would be if your app needed to select an item, say an image, and it wasn’t in an interactive control like a button, so it didn’t support commanding. Using this you can easily set a property in your View Model, even passing in a bound value. Another great use is to interact directly with the UI, where the logic would be inappropriate in the View Model, but equally unnecessary in the code-behind. Some people are intoxicated with putting everything in XAML, and Behaviors let them do almost everything declaratively. It’s a purist’s nirvana.
C# Equivalent: The XAML above is the equivalent to this:
The Control Storyboard Action is handy if you have a stand-alone Storyboard in your XAML tree. A likely scenario is not to have controls like Play and Pause buttons, but instead to use this Action in concert with other actions, like Call Method Action. Using a Storyboard, you can add a visual dynamic to an otherwise behind-the-scenes operation.
The Go to State Action is key to a XAML UI leveraging Visual States. Visual States allow developers to declare their UI as it should be in different logical states. Your buttons are disabled when the user is logged out? That’s a visual state. Your score is visible when playing the game? That’s a visual state. Visual States allow developers and designers to build a UI anticipating certain conditions. The Go to State Action lets you change from one state to another.
In concert with the Data Trigger Behavior, developers can wire up their View Model to change the visual state for them. This solves an age-old problem of responsibility, and removes 90% of the need for messaging solution in a typical MVVM implementation.
Another MVVM convention is the commanding pattern. The Invoke Command Action is part-and-parcel to the declarative commanding pattern. The idea around commands is that the user can invoke an operation in the View Model without having to call to it directly. Moreover, the command speaks back to the UI, disabling interaction controls (like buttons) when their command is not available.
Since commands are almost solely available to buttons, they may be underutilized in most implementations. For example, the selection of an item in a GridView is not a command, but the selection might be important to communicate back to the View Model. Some developers might just add a SelectionChanged handler in the code-behind. This is a classic slippery slope in multi-modal communication with a View Model.
The introduction of Event-To-Command bridges this gap. It basically translates the SelectionChanged event into a Routed Command in the View Model. The problem with this, however, is that it requires an outside library to accomplish. That’s not all that bad, but thanks to the Invoke Command Action, the Event-To-Command is no longer necessary. When used with an Event or Data Trigger Behavior, the Invoke Command Action is very powerful and completes the circle for a proper MVVM implementation.
In Windows Phone, the most popular Action is Navigate To Page Action. It simply accomplishes the most common developer task in a single drag-and-drop step. For that reason, this Action will likely become one of the most popular on the Windows 8 platform, too. It supports parameters, of course, as a literal or bound value – giving you exactly what you need. Should you decide, instead, to use a Navigation Service to handle navigation in your app, then Call Method Action or Invoke Command Action can support you. Either way, navigation doesn’t require code-behind anymore.
The Play Sound Action is exactly what you think it is. In previous versions of XAML the MediaPlayer element allowed developers to play a sound without adding the control to the visual tree. In Windows 8, the MediaPlayer is not present, but the MediaElement is. The MediaElement control must be added to the visual tree in order to play a sound. If you remember that the Blend Behaviors don’t do anything you could do yourself, it makes sense why the MediaElement is at the heart of this Action. It also means you could guess h0ow it works. And, since the MediaElement is the underlying control accomplishing the playback, you get the rich URL handling and broad Media decoding that you would want.
Show me the money!
Let’s take a few minutes and use these Behaviors together.
Now, I have broken the video into two parts because demonstrating every built-in Action takes a little while, and you need to go put the kettle on. Having said that, the first video covers the ChangePropertyAction, the CallMethodAction, and the InvokeCommandAction. In so many ways, these three are the core actions for Blend. But, wait, there’s more.
Above, in the second video, we cover the ControlStoryboardACtion, the OkaySoundAction, the GoToStateAction, and the NavigateToPageAction. All of these utility actions are super-handy to replace otherwise-necessary code-behind. I talk briefly about, not just the EventTriggerBehavior which is useful for monitoring raised events, but also the DataTriggerBehavior which is useful for monitoring changes in property values.
What to say. To know him is to love him. And, when it comes to Behaviors and Actions – what’s not to love? XAML is a great way of declaring a UI, and Blend is a great way of styling and design your user experience while maintaining separation of the design tasks form the coding tasks. With Behaviors and Actions, developers and designers have even more capability on the design canvas to declare both the look and basic operation of a screen.
In fact, it’s not unreasonable that a developer could use Blend and Behaviors with Actions to build a complete solution with no code at all. Granted, this would be more for academic accomplishment than a practical, real-world implementation. Having said that, the fact that Behaviors and Actions even could allow this speaks loudly to the power and capability for designers. For developers, they offer a level of encapsulation that wasn’t otherwise available on the design surface. With Visual Studio 2012, developers lost Behaviors; with Visual Studio 2013, they’re back – and with a simplified IBehavior and IAction interface to streamline custom implementations.
Best of luck!