49

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?

Stefan Wick MSFT
  • 13,600
  • 1
  • 32
  • 51
Josh Close
  • 22,935
  • 13
  • 92
  • 140

8 Answers8

60

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();
}
btlog
  • 4,760
  • 2
  • 29
  • 38
Stefan Wick MSFT
  • 13,600
  • 1
  • 32
  • 51
17

try to set UpdateSourceTrigger property to 'PropertyChanged'

like this

Property="{Binding PropertyBinding, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Rajiv
  • 1,245
  • 14
  • 28
  • 1
    just Property="{Binding PropertyBinding, UpdateSourceTrigger=PropertyChanged}" as twoway is per default – loonix Mar 23 '21 at 22:17
17

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.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
8

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.

Derek Lakin
  • 16,179
  • 36
  • 51
  • 4
    I'm already using MVVM Light and don't want to include Prism just for that. :( – Josh Close Apr 06 '11 at 17:15
  • Well, the source code is available, too, so you could just include that one file ;) – Derek Lakin Apr 06 '11 at 17:37
  • Yeah, that's what I'm looking at right now. I didn't realize how light weight Prism for WP7 actually is. I may have to lookup the differences between Prism and MVVM Light. Prism seems to have a few extra things I need to use. – Josh Close Apr 06 '11 at 17:44
  • 1
    It's a personal preference thing :) Prism for WP7 is **much** lighter than for Silverlight or WPF, but offers most of what you need. MVVM Light has some good points, too, especially EventToCommand; depends what you need. – Derek Lakin Apr 06 '11 at 18:24
  • I've been looking if I can switch completely over to Prism 'cause it looks like it has almost everything I need. If there is no way to do EventToCommand in Prism, maybe I'll just use both frameworks together. They both seem pretty small. – Josh Close Apr 06 '11 at 19:07
  • @Derek, +1 for the very good tipp. I managed to solve my problem with following your advise. – gyurisc May 08 '12 at 07:24
  • Just got this problem with WP8 on MvvmCross, and often having control behavior issues with Android, I put that in the text changed event: `Control.Visibility = Collapsed; Control.Visibility = Visible; Control.Focus()`, which did the trick. – Léon Pelletier Mar 09 '14 at 04:55
  • @DerekLakin an example of how to use `UpdateTextBindingOnPropertyChanged ` with XAML would be great – Junior Apr 21 '18 at 00:17
6

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.

borrillis
  • 656
  • 4
  • 7
Tony Wall
  • 1,382
  • 20
  • 18
6

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!

rrhartjr
  • 2,112
  • 2
  • 15
  • 21
1

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.

PhilChuang
  • 2,556
  • 1
  • 23
  • 29
0

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

jlo
  • 256
  • 1
  • 2
  • 11
  • Extending TextBox doesn't sound like a good idea. It's actually a very bad idea. It's the worst Idea in fact. An AttachProperty might be better.But still this kind of solution limits you to one single control and that's one of the reasons I totally disagree it. what if we want the same behavior on another control? – Hossein Shahdoost Jan 25 '16 at 08:45
  • url included expired – Rajiv Aug 01 '16 at 11:26