Using Behaviors in Windows 8 Store Apps

This short article explains how to write and use behaviors in Windows 8 Store apps. Behaviors were introduced a couple of yahren ago, in Blend for Silverlight 3. Later on they also found their way to WPF and WP7. Technically, behaviors are nothing but an implementation of Attached Properties. Attached properties allow you to define properties in a parent element, and then let all child elements use their own value for these properties. The classroom examples of attached properties are the Grid.Row and Grid.Column that you can assign to any XAML element. The properties themselves are defined as Dependency Properties in the Grid class, but in your XAML you can assign individual Grid.Row and Grid.Column values to every StackPanel, TextBox, or whatever control.


As already mentioned, Behaviors are an implementation of Attached Properties. In a Behavior, the values of the attached properties are used to configure one or more event handlers. The Behavior then hooks these event handlers to the control to which it is attached in XAML. This way you can e.g. create an encapsulated reusable 'AutoComplete' behavior that runs code when the text in a TextBox or ComboBox changes, without creating a separate control, without writing code-behind, and without modifying your viewmodels. On top of that, Behaviors can be combined. If you would like a textbox that does validation, selects all text when it receives the focus, and auto completes user input, then it suffices to create three separate behaviors, and apply these to a regular textbox. Please don’t build your own ValidatingSelectAllOnFocusAutoCompleteTextBox custom control.


I hope I just convinced you that behaviors are really useful in the XAML world. Now here’s the bad news: behaviors are not available for Windows 8 Store apps. But don't panic: @LocalJoost resurrected behaviors and made the code available through CodePlex and Nuget. If you want to use behaviors in a Windows 8 Store app, all you need to do is link the WinRTBehaviors assembly to your project. As you know, I actually prefer embedding the source code directly:

Let’s create the simplest of all behaviors: one that makes a textbox select all its content when it receives the focus, so you can easily overwrite it. The behavior is configured through a SelectAllOnFocus property, a Boolean. 

Here’s how it goes:

Create a class and let it derive from Behavior<T> where T is the type of Control to which you want the behavior to be attached. In our sample, T is TextBox:

public class SelectAllOnFocusBehavior : Behavior<TextBox>
{
  // ...
}

Define and register the attached dependency properties, and provide the standard Get and Set accessors. These accessors are used to access the property values in code behind:

public static readonly DependencyProperty SelectAllOnFocusProperty =
    DependencyProperty.RegisterAttached
    (
        "SelectAllOnFocus",
        typeof(bool),
        typeof(SelectAllOnFocusBehavior),
        new PropertyMetadata(false)
    );

public static bool GetSelectAllOnFocus(DependencyObject obj)
{
    return (bool)obj.GetValue(SelectAllOnFocusProperty);
}

public static void SetSelectAllOnFocus(DependencyObject obj, bool value)
{
    obj.SetValue(SelectAllOnFocusProperty, value);
}

Override the OnAttached and OnDetaching event handlers. The decorated control is available as a strongly typed AssociatedObject of type T. Make sure you unregister event handlers in OnDetaching to avoid memory leaks:

protected override void OnAttached()
{
    base.OnAttached();
            
    if (AssociatedObject != null)
    {
        if (GetSelectAllOnFocus(this))
        {
            AssociatedObject.GotFocus += AssociatedObject_GotFocus;
        }
    }
}

protected override void OnDetaching()
{
    if (AssociatedObject != null)
    {
        if (GetSelectAllOnFocus(this))
        {
            AssociatedObject.GotFocus -= AssociatedObject_GotFocus;
        }
    }

    base.OnDetaching();
}

All scaffolding is in place now. Just implement the core business logic:

private void AssociatedObject_GotFocus(object sender, RoutedEventArgs e)
{
    if (AssociatedObject != null)
    {
        AssociatedObject.SelectAll();
    }
}

That’s all. For the sake of simplicity, I skipped the OnPropertyChanged handling in this article. You can define a handler as the second parameter of the DependencyProperty.RegisterAttached call. That handler will be called when a dependency property was modified, e.g. through data binding You’ll find some more elaborate examples here.

All you now need to do is attach the behavior to a XAML element (a TextBox in this case) and set the properties. Note that you have to define a behavior collection and fill it with behavior instances, like this:

<TextBox Text="Joined the Dark Side, I have."
         FontSize="18"
         Margin="8">
    <WinRtBehaviors:Interaction.Behaviors>
        <local:SelectAllOnFocusBehavior SelectAllOnFocus="True" />
    </WinRtBehaviors:Interaction.Behaviors>
</TextBox>

The following code does NOT work:

<TextBox Text="Joined the Dark Side, I have."
         FontSize="18"
         Margin="8"
         local:SelectAllOnFocusBehavior SelectAllOnFocus="True" />

 

Here are some screenshots of the attached sample app. The first textbox has SelectAllOnFocus to true, its whole content is selected when it receives the focus:

The second textbox has SelectAllOnFocus to false, no text is selected, the caret sits in front of the text:

Here’s the code, it was written in Visual Studio 2012 Express: U2UConsult.WinRTBehaviors.Sample.zip (126.55 kb).

Enjoy!
Diederik