none
TextBox TextChanged event doesn't cause data binding to update

    Question

  • I have a text box that is bound (two way) to the following property:

     private String m_description;

            public String Description
            {
                get { return m_description; }
                set
                {
                    m_description = value;
                    this.OnPropertyChanged("Description"); // This goes on to call the INotifyPropertyChanged.PropertyChanged event
                }
            }

    But the data binding is only ever updated when the text loses focus. The TextChanged event does fire, but it doesn't  update the binding.

     I've had a look at the BindingExpression code via Reflector:

      if (this._targetObject is TextBox)
            {
                this._targetIsTextBox = true;
                TextBox box = this._targetObject as TextBox;
                box.LostFocus += new RoutedEventHandler(this.TargetTextBoxLostFocus);
                if (this._targetProperty == TextBox.TextProperty)
                {
                    box.TextChanged += new TextChangedEventHandler(this.TargetTextBoxTextChanged);
                }
            }


    It looks like it *should* work, but it isnt? The TargetTextBoxLostFocus function is definitely being called, I can see that in the call stack.

    Any ideas?

    Mark Ingram

    Wednesday, November 19, 2008 11:11 AM

Answers

  • That, unfortunately, is the way TextBox works.  The only way to have the TextBox update a two-way binding is to cause it to lose focus.  If you want to trigger the binding on every character input, you need to focus to the TextBox's parent then back to the TextBox when you get the key press.  I can only imagine what side-effects this might have.

    It's really ugly.  It would be nice to have a function on the TextBox like "UpdateBindings()" or something.  Then you could decide when to update the binding.

    Your question is a variation on another question on the forum regarding updating the binding only when the user presses Enter in the TextBox.  That's not possible either.

     

    Wednesday, November 19, 2008 4:44 PM
  • Hey,

    Currently Silverlight binding engine updates source only when TextBox loses focus, or when you set the Text property from code. When you look at TargetTextBoxChanged method, it just changes internal state of the BindingExpression, but does not write the value back to the source.

    Regards,
    Tomek

    Saturday, November 22, 2008 12:28 AM

All replies

  • That, unfortunately, is the way TextBox works.  The only way to have the TextBox update a two-way binding is to cause it to lose focus.  If you want to trigger the binding on every character input, you need to focus to the TextBox's parent then back to the TextBox when you get the key press.  I can only imagine what side-effects this might have.

    It's really ugly.  It would be nice to have a function on the TextBox like "UpdateBindings()" or something.  Then you could decide when to update the binding.

    Your question is a variation on another question on the forum regarding updating the binding only when the user presses Enter in the TextBox.  That's not possible either.

     

    Wednesday, November 19, 2008 4:44 PM
  •  But looking at the code in the BindingExpression class, it looks like it *should* work?

    I've got around it by manually updating my data in the data context in the TextChanged method. It's not nice though.

    Wednesday, November 19, 2008 5:04 PM
  • Hey,

    Currently Silverlight binding engine updates source only when TextBox loses focus, or when you set the Text property from code. When you look at TargetTextBoxChanged method, it just changes internal state of the BindingExpression, but does not write the value back to the source.

    Regards,
    Tomek

    Saturday, November 22, 2008 12:28 AM
  • I ran over the same isssue. Not sure what's best to do now...

    I wonder if there is a reason for why binding was implemented like this or if it's just bad design/a slip.

    Monday, August 03, 2009 5:33 AM
  • I wonder if there is a reason for why binding was implemented like this or if it's just bad design/a slip.

    I'm guessing it has to do with validation. If it changed the underlying binding object on every keystroke, and there was something like a minimum length requirement, it would cause pre-mature validation errors.

    Wednesday, August 26, 2009 5:02 PM
  • Mmm...

     I thought there was a way to choose whether you want in textbox to propagate the value to the binded property on focus or new character typed, seems not :-(.

     I use the same workaround TextboxChanged change the property... ugly stuff.

     Is not good that a technology forces you to follow a way for the functional flow of the app (e.g. enabling button when the textbox change not supported or just by a workaround.... you have to enable the button always and show error information in the case the textbox didn't contain what you expected :-( ).

    Cheers

       Braulio

    Friday, September 25, 2009 10:17 AM
  • The only way to have the TextBox update a two-way binding is to cause it to lose focus

    You can manually trigger the update of the source by calling UpdateSource() on the BindingExpression, which can be retrieved by calling GetBindingExpression on the TextBox.

    This is not a bug or an oversight. Lots of automatic features have been cut to keep the Silverlight plugin as small as possible. In this case, you can see in WPF a "PropertyChanged" member on the UpdateSourceTrigger enum. This member does not exist in Silverlight.

    • Proposed as answer by Square.HipToBe Friday, January 25, 2013 10:44 PM
    Friday, September 25, 2009 11:26 PM
  • Thanks nelligan for your response...

    Well... is not a bug... it's lack of functionallity. But I find it something serious beacuse it affects the functional side of an application, What if my client has an standard on validations (e.g. enable save button just when the textbox has a valida value) ? I have to say him... well... we have to use a lot of manual hacks to make this work :-(.

    I thought that this was fixed /enhanced on SL 3.0, or maybe some control on the toolkit... don't know, but it's a pity having to go with workarounds to acomplish a quite standard and well know functionallity.

    Saturday, September 26, 2009 4:32 PM
  • Well.. I have encapsulated the workaround in an user control... to make it a bit less painful

     

    Well.. encapsulated in a user control the workaround...

    public class TextBoxChangeExt : System.Windows.Controls.TextBox

    {

    public TextBoxChangeExt()

    {

    this.TextChanged += new TextChangedEventHandler(TextBoxChangeExt_TextChanged);

    }

    void TextBoxChangeExt_TextChanged(object sender, TextChangedEventArgs e)

    {

    // based on

    // http://betaforums.silverlight.net/forums/t/103695.aspx

    TextBox txCtl = (TextBox)sender;if (txCtl != null)

    {

    var be = txCtl.GetBindingBLOCKED EXPRESSION

    {

    be.UpdateSource();

    }

    }

    }

    }

    Tuesday, September 29, 2009 8:49 AM
  • This can be easily solved using behaviors. Very simple solution. Check the link below.

    http://zoltanarvai.wordpress.com/2009/07/22/binding-update-on-textbox-textchanged-event-using-behaviors/

    Sunday, October 24, 2010 11:58 PM
  • If you want to update the TextBox source when something else is done, such as pressing Enter to save the content, then you can place this code in a library for use by all pages:

    public static void UpdateSource() {
        // If a TextBox has the focus, this forces it to update its source.
        // It is needed when using Enter and Escape to activate Save and Cancel button,
        // because the focused TextBox does not update in Silverlight, even when
        // a call is made to ButtonSave.Focus() or ButtonCancel.Focus().
        TextBox tb = FocusManager.GetFocusedElement() as TextBox;
        if (tb != null)
            tb.GetBindingExpression (TextBox.TextProperty) . UpdateSource();
    }

    Then you call it before saving.  For example, in the Click event for a window, control, or page, you can have this:

    private void LayoutRoot_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) {
        UpdateSource();
        if (e.Key == Key.Enter)
            ButtonSave_Click(null, null);
    }

    Sunday, December 26, 2010 4:08 PM
  • You can manually trigger the update of the source by calling UpdateSource() on the BindingExpression, which can be retrieved by calling GetBindingExpression on the TextBox.

    First class! Solved this for me right out of the gates. For anyone else's reference this handler applied to any text box's TextChanged event should take care of it for you:

           

    private void TextBox_TextChanged(object sender, TextChangedEventArgs e)

            {

    TextBox src = (TextBox)sender;

    src.GetBindingExpression(TextBox.TextProperty).UpdateSource();

            }

    Tuesday, September 20, 2011 12:04 PM
  • Just if somebody needs it for a PasswordBox (99 % same code).

    public class UpdateOnPasswordChangedBehavior : Behavior<PasswordBox>

        {

           

    protected override void OnAttached()

            {

               

    base.OnAttached();

               

    this.AssociatedObject.PasswordChanged += new System.Windows.RoutedEventHandler(AssociatedObject_PasswordChanged);

            }

           

    void AssociatedObject_PasswordChanged(object sender, System.Windows.RoutedEventArgs e)

            {

               

    BindingExpression binding =

                   

    this.AssociatedObject.GetBindingExpression(PasswordBox.PasswordProperty);

               

    if (binding != null)

                {

                    binding.UpdateSource();

                }

            }

     

           

    protected override void OnDetaching()

            {

               

    base.OnDetaching();

               

    this.AssociatedObject.PasswordChanged -=

                   

    new System.Windows.RoutedEventHandler(AssociatedObject_PasswordChanged);

            }

        }

    Wednesday, November 09, 2011 5:49 AM