47
votes

I have a page with some text boxes for data input. The binding of the text box is set to TwoWay. The data in my view model only gets updated if the text box loses focus. If I click a button, such as save, and the text box still has the focus, the changes in the text box aren't changed in my view model on the save event.

Is there a way to have the binding save the value of the text box before it loses focus? Or do I need to do something in the save event?

8
Here you can find a working solution updating the binding on the TextChanged event: stackoverflow.com/a/4833196/928955breigo
Same issue on WP8, @StefanWick answer solved it for me.D.Rosado

8 Answers

8
votes

You can use the UpdateTextBindingOnPropertyChanged behavior from the Prism Library for WP7 to update the bound value when the text changes instead of on lost focus.

58
votes

I assume your Save button is an ApplicationBarButton (not a normal button). For normal buttons it will just work because they take focus and hence the data-binding will kick in.

For ApplicationBarButtons on the phone it's a little different because they don't take focus away from the client app. To ensure the data-binding kicks in when your Save button is clicked, you can add the following code in your handler:

object focusObj = FocusManager.GetFocusedElement();
if (focusObj != null && focusObj is TextBox)
{
    var binding = (focusObj as TextBox).GetBindingExpression(TextBox.TextProperty);
    binding.UpdateSource();
}
16
votes

Download Charles Petzold's free book Programming Windows Phone 7. On page 387 he talks about how to do this.

Basically, set the UpdateSourceTrigger property of the Binding to Explicit. Then, in the TextBox's TextChanged callback, update the Binding source.

14
votes

try to set UpdateSourceTrigger property to 'PropertyChanged'

like this

Property="{Binding PropertyBinding, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
6
votes

I'm going in the opposite direction of @Praetorian.

Your TextBox has a default UpdateSourceTrigger value of LostFocus. This means the value is only pushed to your ViewModel property when.. it loses focus.

You can set the UpdateSourceTrigger to PropertyChanged:

<TextBox UpdateSourceTrigger="PropertyChanged" Text="{Binding TextViewModelProperty}" />

From http://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger.aspx:

One of the UpdateSourceTrigger values. The default is Default, which returns the default UpdateSourceTrigger value of the target dependency property. However, the default value for most dependency properties is PropertyChanged, while the Text property has a default value of LostFocus.

Keep in mind this means that anything that is trigger by an update to this property will happen much more frequently (basically with every keypress, instead of a single "flush" when the TextBox loses focus).

Hope that helps!

6
votes

Here's a quick access answer to the Microsoft solution suggested by Derek. Rather than downloading and sifting through all the Prism stuff, just copy this class into your project then follow the steps afterwards to activate it:

UpdateBindingOnPropertyChangedBehviour.cs

using System;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;

namespace MyCompany.MyProduct
{
    /// <summary>
    /// Custom behavior that updates the source of a binding on a text box as the text changes.
    /// </summary>
    public class UpdateTextBindingOnPropertyChanged : Behavior<TextBox>
    {
        /// <summary>
        /// Binding expression this behavior is attached to.
        /// </summary>
        private BindingExpression _expression;

        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        /// <remarks>
        /// Override this to hook up functionality to the AssociatedObject.
        /// </remarks>
        protected override void OnAttached()
        {
            base.OnAttached();

            // Hook events to change behavior
            _expression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
            AssociatedObject.TextChanged += OnTextChanged;
        }

        /// <summary>
        /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        /// <remarks>
        /// Override this to unhook functionality from the AssociatedObject.
        /// </remarks>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            // Un-hook events
            AssociatedObject.TextChanged -= OnTextChanged;
            _expression = null;
        }

        /// <summary>
        /// Updates the source property when the text is changed.
        /// </summary>
        private void OnTextChanged(object sender, EventArgs args)
        {
            _expression.UpdateSource();
        }
    }
}

This is basically a cleaned-up version of the Microsoft Prism 4.1 code (see the Silverlight\Prism.Interactivity project if you want to browse the rest).

Now how to use it:

  1. Add a reference to System.Windows.Interactivity assembly to your Windows Phone project.
  2. In each page where you want to use the behaviour, add a XAML reference to the assembly: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
  3. Inside the XAML of each TextBox to which you want to apply the bahvior (which already has a TwoWay binding to your source property), add the following:

    <i:Interaction.Behaviors>
    <my:UpdateTextBindingOnPropertyChanged />
    </i:Interaction.Behaviors>

    Note: the "my:" prefix may be different in your code. It's just the namespace reference where you added the behaviour class.

1
votes

I haven't tried @Praetorian's answer so if that works well then do that - otherwise, use both the KeyUp AND TextChanged events to update the Binding source.

0
votes

This link has a solution that worked perfectly in WinRT. He inherits TextBox and adds a new property: BindableText.

http://www.familie-smits.com/post/2012/07/29/UpdateSourceTrigger-in-WinRT.aspx