Input Focus from the View Model – Configured via Blend Behaviors
Background / Focus of this Article
WPF wizard and fellow WPF Disciple Josh Smith published an article yesterday that showed how to control input focus from View Model objects using attached properties and a custom binding extension. Prior to the article, there was a discussion in the Disciples group, during which I looked into using Blend behaviors as an alternative configuration approach to Josh’s markup extension – this article here discusses this approach.
Accordingly, this posting is not about controlling input focus. Josh did all the legwork there, and you should check out the article on his blog. Everything that goes beyond the Behavior classes is Josh’s work, not mine – I merely discuss a different approach regarding the declaration of focus control on the UI using Blend Behaviors.
Download Source Code and Sample Application
Differences
Let’s start by looking at the difference from a developer’s point of view. Assume you have a simple TextBox control that is bound to a FirstName property on the View Model:
<!-- simple textbox --> <TextBox Text="{Binding FirstName}" />
Markup Extensions – One for the XAML Guys / Gals
Josh’s approach using a markup extension is a very lean way to wire up your control with the focus controller. If you’re used to coding in XAML, this is pretty much the quickest way to get things running. Note that only the Binding keyword was replaced by a the custom FocusBinding markup extension:
<!-- simple textbox --> <TextBox Text="{jas:FocusBinding FirstName}" />
If you’re working in Visual Studio, this is the way to go (even more so if you have ReSharper to take care of the namespace declarations for you). It might become tedious, however, if’ you’re working in a Blend environment: For one thing, there’s the namespace declarations. And then, you can no longer wire up your bindings directly in Blend on the designer surface.
Blend Behaviors – Designer’s Flavor
The Blend Behaviors don’t require you to write any XAML at all. The data binding itself remains unchanged, and the TextBoxFocusBehavior was just dragged/dropped on the TextBox in Blend. Accordingly, you can set up both binding and input focus control with a few mouse clicks without having to leave the designer surface:
If you look at XAML source, you’ll notice that the Behavior above actually produces substantially more markup – this isn’t something you’d want to type in manually:
<TextBox Text="{Binding FirstName}" > <i:Interaction.Behaviors> <FocusVMLib_Behaviors:TextBoxFocusBehavior/> </i:Interaction.Behaviors> </TextBox>
In order to compare the two approaches, just download the attached sample and have a look at the two Window classes. Window1 is the original implementation (using the markup extension), Window2 uses the Blend behaviors. The end result is the same – the only difference is the different declaration approaches.
The Behavior Classes
The rest of this blog post discusses the implementation of the behavior classes, and suggests an approach to support different control types.
A Problem: Where to get the Bound Property?
Josh’s focus helper library uses the binding between the UI and the View Model in order to observe the View Model for a change on a relevant property.
Accordingly, the Blend Behavior needs to determine the bound property somehow in order to submit it to the FocusController class. Basically, there’s two solutions:
- Write control-aware Behaviors that implicitly use the correct property.
- Write a Behavior that lets you specify the bound property at design time.
I decided to support both approaches. The sample application consists of three classes:
- An abstract base class that wires up the control in order to take part in focus control.
- A generic Behavior class that allows to specify the bound property manually.
- A exemplary Behavior that can be used on TextBox controls without having to do any further configuration. You will see that you can create similar classes for other controls in a matter of seconds.
The FocusBehaviorBase Class
This abstract base class takes care about wiring up the associated UI element with the FocusController of Josh’s focus helper library:
public abstract class FocusBehaviorBase : Behavior<FrameworkElement> { protected abstract DependencyProperty GetSourceProperty(); protected override void OnAttached() { //get the bound property discovery DependencyProperty sourceProperty = GetSourceProperty(); //delegate focus handling FocusController.SetFocusableProperty(AssociatedObject, sourceProperty); } }
As you can see in the snippet above, the base class delegates the job to resolve the bound property via the abstract GetSourceProperty method. This property, along with the associated object, is then forwarded to the FocusController class which takes care of the rest.
Generic but Complex Behaviors
The first working Behavior implementation is a generic version that lets you specify the bound property yourself. As such, the class exposes a BoundSource property, which takes an arbitrary DependencyProperty. The GetSourceProperty method then just returns that property:
public class CustomFocusBehavior : FocusBehaviorBase { public static readonly DependencyProperty BoundSourceProperty = DependencyProperty.Register("BoundSource", typeof (DependencyProperty), typeof (CustomFocusBehavior)); public DependencyProperty BoundSource { get { return (DependencyProperty)GetValue(BoundSourceProperty); } set { SetValue(BoundSourceProperty, value); } } protected override DependencyProperty GetSourceProperty() { //return the property value to the base class return BoundSource; } }
This class is already sufficient to cover any binding scenarios, but it requires you to specify the property yourself with a rather unusual binding expression (you are not binding to a property value, but a dependency property itself):
The advantage of this generic Behavior is that you can bind to arbitrary properties. On the other hand, it’s obvious that this approach isn’t exactly designer friendly, which is why I’d recommend to simplify things for common controls with custom Behaviors.
Controls Specific Behaviors
The FocusBehaviorBase class expects only one thing from an implementing class: Information about a bound property. This makes it extremely simple to create control-aware behaviors. The sample application contains one example that can be used with TextBoxes, called TextBoxFocusBehavior. The implementation is trivial:
public class TextBoxFocusBehavior : FocusBehaviorBase { protected override DependencyProperty GetSourceProperty() { return TextBox.TextProperty; } }
A behavior like this requires no additional configuration if you are working in Blend. Just drag and drop the behavior on the control and be on your way. And of course, nothing stops you from writing your own behavior classes.
As an additional example, here’s a behavior that covers all controls of type ToggleButton, which includes checkboxes and radio buttons:
//this also covers CheckBox and RadioButton public class ToggleFocusBehavior : FocusBehaviorBase { protected override DependencyProperty GetSourceProperty() { return ToggleButton.IsCheckedProperty; } }
You could also write a Behavior that looks at the AssociatedObject before returning a property, or one that takes a string argument and resolves the dependency property via reflection. Basically, there’s no limits here. However, I assume you will probably only have to write a few behaviors to cover your whole application – accordingly, I’d recommend you to write simple behaviors such as the TextBoxFocusBehavior.
Conclusion
Behaviors are a very convenient way if you are working in Blend. Just dropping a few behaviors on your controls is more comfortable than tampering with XAML, and the bindings remain untouched, so you can edit them in Blend at any time.
On the other hand, if you’re working with Visual Studio, or if you are used to set up your bindings directly in XAML anyway, just using the markup extension is the faster and leaner choice.
In my opinion, the two approaches complement themselves. Both are just means to wire up your controls with the View Model, so the outcome is the same. In the end, it’s about preference.
Awesome post Philip
Cheers Sacha 🙂
great post as usual!
Great post! but I meet a problem. if the Binding skeleton as below:
RootViewModel->ModeList->SelectedItem->Name
The textbox binding to Name.
var focusMover = element.GetValue(FrameworkElement.DataContextProperty) as IFocusMover;
wont’t get the RootViewModel. How can I do?