One of the odd things of having been around the XAML platforms (WPF, Workflow, Silverlight, Windows Phone and then Windows 8) for a while is that certain pieces of functionality have come and gone along the journey from the initial introduction of XAML with WPF back with Windows Vista in 2006 through to the latest iteration of a “XAML platform” which I guess is the XAML stack in Windows 8.1.
An example that I was talking to someone about yesterday would be binary XAML. I remember BAML first time around and so it was interesting to see that reappear in Windows 8.1 with the XBF format.
Another example would be the Behaviours work that Blend introduced back in 2009. While I can’t remember it, it looks like someone claiming to be me wrote a little about it back in 2009 and again in May of that year. I have no recollection whatsoever of writing those posts but I guess it must have been me that did it.
Back here in 2013, it’s nice to see Blend for Visual Studio 2013 bringing back some of its behaviors to Windows 8.1 app development.
Dropping into Blend and making a blank project shows the available behaviors within the assets menu;
although (as I talked about in my post 4 years ago) – strictly speaking these are a mixture of behaviors and actions but they all get labelled as behaviors here in the tool.
If you’ve seen these things before then there’s probably not much more to say about them coming back to Windows 8.1. If you’ve not seen them before then let’s run through what they are. It’s worth saying that the set of behaviors that come with Blend for Visual Studio 2013 look to be supported in both C++ XAML projects and in .NET XAML projects (implemented in BehaviorsXamlSDKManaged.dll)
EventTriggerBehavior
An event trigger behavior is a simple thing. If you look at the definition of it;
then this behavior can be Attached to anything that derives from DependencyObject but I guess that’s most likely to be some kind of UIElement and its basic role in life is to sync itself up to some event named EventName on the AssociatedObject and when that event fires, this behavior will go ahead and execute the Actions.
So, it’s a generic object that attaches to another object, waits for some specified event to occur and then executes a set of actions in response to that event.
What Actions have we got to play with?
- CallMethodAction – i.e. call some method on some object, most likely with that object coming from the data context.
- ChangePropertyAction – i.e. change some property on some object.
- ControlStoryboardAction – i.e. do something with a storyboard.
- GoToStateAction – i.e. drive the visual state manager to some state
- InvokeCommandAction – i.e. invoke some implementation of ICommand on the DataContext
- NavigateToPageAction – i.e. speaks for itself!
- PlaySoundAction – i.e. speaks for itself too.
As an example, let’s say that I place some simple UI elements onto the design surface – 3 buttons and a rectangle as below;
then I can drag out a “EventTriggerBehavior” to each button;
and then I can configure those behaviors to choose a particular event trigger such as (e.g.) the Button’s click event;
The next thing to do is to choose one of those actions that all do different things for me.
Change Property Action
If I make use of a ChangePropertyAction;
then I can configure each one of the buttons on the screen to change a property of an object – for example here’s choosing to change the Fill of the Rectangle on the screen to be red;
and so I can have 3 buttons that change this rectangle to red/green/blue Fill without writing any code as such – it’s all just declarative and I end up with XAML that looks like;
<Button Content="blue" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="106,234,0,0"> <Interactivity:Interaction.Behaviors> <Core:EventTriggerBehavior EventName="Click"> <Core:ChangePropertyAction TargetObject="{Binding ElementName=rectangle}" PropertyName="Fill"> <Core:ChangePropertyAction.Value> <SolidColorBrush Color="#FF0015FF"/> </Core:ChangePropertyAction.Value> </Core:ChangePropertyAction> </Core:EventTriggerBehavior> </Interactivity:Interaction.Behaviors> </Button>
This idea of changing a property’s value is pretty generic so, as a second example, let’s say that I define this class;
class TShirt { public TShirt() { } public double Price { get; set; } }
and define an instance in my XAML (it could be my DataContext or, as here, I’m just dropping an instance in as a resource on the page);
<Page.Resources> <local:TShirt x:Name="shirt"/> </Page.Resources>
then I could tweak my ChangePropertyAction to change that Price value on that TShirt object;
and that all works quite nicely.
Call Method Action
The name’s pretty descriptive – in the same way as the previous action could change a property, this action can call a method for you on an object. I might have a class like this;
class MessageHelper { public async void ShowMessage() { MessageDialog dialog = new MessageDialog("Hello"); await dialog.ShowAsync(); } }
and I might define an instance in my resources;
<Page.Resources> <local:MessageHelper x:Key="helper"/> </Page.Resources>
and then I could invoke that method declaratively from this trigger;
and get that method invoked declaratively from the UI with no real coupling ( beyond a couple of strings ) between the UI and the code that gets run. That said, the absence of an ability to pass a parameter might be a limitation so it’s perhaps more likely that I’d want to invoke a method on some kind of ViewModel object residing in the DataContext so changing things slightly;
class ViewModel { // Not doing property change notification public string Text { get; set; } public void DisplayMessage() { MessageDialog dialog = new MessageDialog(this.Text); dialog.ShowAsync(); } }
and an instance of this could be set as the DataContext for perhaps a TextBox and a Button;
<StackPanel HorizontalAlignment="Left" Height="364" Margin="871,66,0,0" VerticalAlignment="Top" Width="335"> <StackPanel.DataContext> <local:ViewModel /> </StackPanel.DataContext> <TextBox Text="{Binding Text,Mode=TwoWay}" /> <Button Content="click Me"> </Button> </StackPanel>
and then a CallMethodAction can be applied as in the screenshot below where the target object is being picked up by binding;
in many ways this CallMethodAction is similar to using an ICommand in that the UI only knows about the name of a method, it doesn’t know anything about where that method is implemented and so a different implementation could be dropped in as a DataContext.
If you wanted to go a step further and make use of an ICommand implementation then you’d be wanting this next class…
InvokeCommandAction
If you’ve got a bit of UI like a GridView and you want to invoke an ICommand implementation when (e.g.) the selection changes on the GridView then you can’t easily do it without additional help either from a library or by writing some more code yourself. There’s an event that fires when the selection changes but there isn’t some property of type ICommand that you can bind to your view model.
A combination of EventTriggerBehavior and InvokeCommandAction can solve that – for a simple view model like this;
class ViewModel { public ViewModel() { this.DisplayMessageCommand = new SimpleCommand( OnDisplayCommand); } void OnDisplayCommand() { MessageDialog dialog = new MessageDialog(this.Text); dialog.ShowAsync(); } public string Text { get; set; } public ICommand DisplayMessageCommand { get; set; } }
and then I could create a GridView with an instance of this object as its DataContext and use the trigger and behavior to wire things up such that a change of selection will cause the command to be invoked with the right parameter. You could argue whether it’s good/bad to pick up the selected value directly from the GridView as I’m doing here via element property binding or whether to bind the selected value to the view model as well and pick it up that way;
<GridView x:Name="gridView"> <Interactivity:Interaction.Behaviors> <Core:EventTriggerBehavior EventName="SelectionChanged"> <Core:InvokeCommandAction Command="{Binding DisplayMessageCommand}" CommandParameter="{Binding SelectedValue, ElementName=gridView}"/> </Core:EventTriggerBehavior> </Interactivity:Interaction.Behaviors> <GridView.Items> <x:String>One</x:String> <x:String>Two</x:String> <x:String>Three</x:String> </GridView.Items> <GridView.DataContext> <local:ViewModel /> </GridView.DataContext> </GridView>
ControlStoryboardAction
I think it’s fair to say that the manual use of animations in Windows Store applications is fairly rare. Things have changed from the early days of WPF/Silverlight where developers were largely left to figure out whether they wanted to animate parts of their UI and, probably, that led to some over-zealous use of animations which encouraged the platform teams to do more work in terms of building standard, consistent animations into their frameworks and controls (e.g. in the way that the built-in Windows 8 controls like a GridView has transitions for items being inserted/removed from the view).
Regardless, if you do want to control an animation manually then this ControlStoryboardAction provides an easy way to do it declaratively and I can create (purely by way of example) some kind of animation for a piece of my UI then associate a ControlStoryboardAction with a particular trigger in order to manipulate the storyboard without writing any code.
In the picture below I’ve hand-drawn a shape and then create a Storyboard to spin it through 360 degrees over 1 second;
I can then add a Button (e.g.) onto the UI, add a EventTriggerBehavior for that Button’s click event and then associate a ControlStoryboardAction with that behavior such that it executes when the event fires;
and the different options that I’ve got for that ControlStoryboardOption are as shown in the dropdown below;
One of the main uses of storyboards is to collect them up and make use of them to drive visual state transitions in the UI so it’s not surprising that there’s another type of action which can do that declaratively…
GoToStateAction
Lets say that I have an app that has 2 different layouts for the UI. Perhaps I have an image and some text and sometimes I want to lay these out side by side;
and sometimes I want to lay them out vertically which I’ve done here by defining a second visual state and moving the items around a little in terms of their grid row/column and grid rowspan/columnspan;
then it’s very easy for me to add (e.g.) an application bar with buttons that would switch into those visual states using the GoToStateAction;
it’s a long way from manually writing code to show/hide pieces of UI
NavigateToPageAction
I guess this one pretty much speaks for itself. If I make a quick project with 2 pages that perhaps look something like;
Then I can easily set up an EventTriggerBehavior for that TextBlock on the first page;
and then wire that to a NavigateToPageAction to move the app on to the second page;
and that’s nice and easily done although I’d have to perhaps have a think as to whether that was how I wanted navigation to work in my app.
One of the interesting things about how declarative this can be is that I actually did that in a C++ project rather than a C# project and hadn’t realised until I came to compile.
PlaySoundAction
This is a relatively easy one, the PlaySoundAction allows you to associate a sound with a trigger meaning that you don’t have to write code or have a hidden MediaElement in order to get a simple sound played.
which seems pretty good to me.
That’s all of the different actions that are shipped, what about the other behaviors?
DataTriggerBehavior
As the name suggests, this is a behaviour that can monitor a particular data value and then perform a logic comparison operator on the data value and execute a number of actions if the logic comparison evaluates to true.
As an example, if I have a slider where for a value < 50 I want to display a green rectangle and for a value >= 50 I want that rectangle to be red;
then it’s easy to build that up declaratively using 2 DataTriggerBehavior instances – here’s one;
and that instance is configured to bind to the Value property of the Slider and if the value is LessThan 50 then it will execute its action which in this case is a ChangePropertyAction configured to change the Fill of the Rectangle to green.
There’s another instance of DataTriggerBehavior making the rectangle red for the reverse case.
The behavior doesn’t have to bind up to some property of a UI control though. It can equally be “watching” a value from a non visual object such as a ViewModel and then executing some set of actions in response to data changes.
As a “for instance”, if I have this crazy view model which keeps toggling some temperature value from a low temperature to a high temperature and which is firing property change notifications;
class ViewModel : ViewModelBase { public ViewModel() { this.ctx = SynchronizationContext.Current; this.Temperature = 80; Timer t = new Timer( _ => { ctx.Post(o => { this.Temperature = this.Temperature == 80 ? 20 : 80; }, null); }, null, 5000, 5000 ); } public int Temperature { get { return (this.temperature); } set { base.SetProperty(ref this.temperature, value); } } int temperature; SynchronizationContext ctx; }
and if I set this as the DataContext for a Grid in my UI which contains a Rectangle then I can define a DataTriggerBehavior to watch for the values changing in that data-bound Temperature value and, for example, if the value is “low” then I could use a ChangePropertyAction to change the colour of the rectangle to blue;
while the screenshot doesn’t show it, that trigger is bound to the property Temperature – it just doesn’t show up in Blend’s UI above and it’s that property whose value is going to trigger whatever actions I add to this behavior whenever the value goes below 50.
IncrementalUpdateBehavior
The last behavior that ships in the box for Windows 8.1. Store apps is the IncrementalUpdateBehavior and I think it’s quite different from the other behaviors listed here.
This behavior relates to scenarios where you’re working with large lists of data and displaying data-templated UI where you want to take control and optimise the order in which the system attempts to render the different content within those templates to provide the user with the best experience while they are panning and flicking through long lists of data.
It’s deep enough to require a separate post so I’ll come back to this one in a subsequent post.