Keeping it focused

Well, it’s been a while since I’ve blogged, as I’ve been a busy little bee working on CodeStash. I feel guilty about this, so I’d like to take the chance to pass on the solution to a problem that was posted on Code Project today. The scenario goes like this:

You have a ViewModel with some text that you want to be updated, and you do all the usual binding work with some TextBox elements. The thing is, you want to update your ViewModel properties when the TextBox loses focus. OK, so that’s easily achieved – in fact, it’s the default behaviour of the TextBox. However, you have a button with IsDefault set on it, so pressing Enter in the TextBox triggers the button click – but as the TextBox hasn’t lost focus, the property you are binding to doesn’t get updated. This is, of course, a problem. Fortunately, there’s an easy little trick that you can deploy to update the property, and it’s easily achieved using an attached behavior.

All you need to do is associate the behaviour to the Button you have set the IsDefault property on, and Bob is your mothers brother, the Text property updates. So, what does this behavior look like:

using System.Windows.Interactivity;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;
using System.Windows.Data;
/// <summary>
/// Associate this behaviour with the button that you mark as IsDefault
/// to trigger the ViewModel update when the user clicks enter in a textbox
/// and the property doesn't update because the update source is set to
/// lost focus.
/// </summary>
public class DefaultButtonUpdateTextBoxBindingBehavior : Behavior<Button>
{
    /// <summary>
    /// Hook into the button click event.
    /// </summary>
    protected override void OnAttached()
    {
        AssociatedObject.Click += AssociatedObject_Click;
        base.OnAttached();
    }

    /// <summary>
    /// Unhook the button click event.
    /// </summary>
    protected override void OnDetaching()
    {
        AssociatedObject.Click -= AssociatedObject_Click;
    }

    /// <summary>
    /// The click event handler.
    /// </summary>
    void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        // Get the element with the keyboard focus
        FrameworkElement el = Keyboard.FocusedElement as FrameworkElement;
        if (el != null && el is TextBox)
        {
            // Get the binding expression associated with the text property
            // for this element.
            BindingExpression expression = el.GetBindingExpression(TextBox.TextProperty);
            if (expression != null)
            {
                // Now, trigger the update.
                expression.UpdateSource();
            }
        }
    }
}

As you can see, there’s not that much code needed. Basically, we get the element that has focus, and retrieve the binding expression associated with it. Once you get the binding expression, we trigger the update.

I’ve copied this behaviour into CodeStash – the handy repository that I will be putting future snippets in for your delectation.

About these ads
  1. July 6, 2012 at 11:16 am

    Excellent article Pete, thanks for sharing. Just found one minor typo, I think in the OnDetaching method, it should be -= for unhooking.

    • peteohanlon
      July 8, 2012 at 7:56 pm

      Thanks for that. I can’t believe I did that. The post is updated now.

  2. July 9, 2012 at 8:05 am

    Nice one pete, thanks for sharing!

  3. Sesharaman
    November 13, 2012 at 3:37 am

    From whatever little I read and understood/misunderstood?, the problem of updating a TextBox in viewmodel is done by me using a variable bound to the said TextBox, in ViewModel which is implementing INotifyPropertyChanged.

    • peteohanlon
      November 21, 2012 at 10:10 pm

      Sesharaman – the issue is a very specific one here. In general, you are right, but there is a scenario whereby you have decided that you want to update your property on the LostFocus event, and not PropertyChanged. Now, if you move your cursor out of this field, the LostFocus will happen and the property will be updated. That’s all well and good.

      Now, suppose that you also have a button on this form and this button has the IsDefault property set to true. Go back into the TextBox and make some changes, then press Enter – the TextBox doesn’t lose focus, but the default button behaviour is triggered; resulting in the property not being updated. That’s what this code does – it sorts that out. Just attach this behaviour to the button, and it triggers the update on the focused element.

      I hope that it is clear now.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Canny Coder

Java 8 Functional Programming with Lambda Expressions

pihole.org

Adventures in theoretical computer science, with your host, chaiguy1337

Confessions of a coder

Confessions of a WPF lover

WordPress.com

WordPress.com is the best place for your personal blog or business site.

Follow

Get every new post delivered to your Inbox.

Join 39 other followers

%d bloggers like this: