34

Is there a way to get a TextBox in Windows Phone 7 to update the Binding as the user types each letter rather than after losing focus?

Like the following WPF TextBox would do:

<TextBox Text="{Binding Path=TextProperty, UpdateSourceTrigger=PropertyChanged}"/>
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Jason Quinn
  • 2,443
  • 3
  • 28
  • 36

8 Answers8

51

Silverlight for WP7 does not support the syntax you've listed. Do the following instead:

<TextBox TextChanged="OnTextBoxTextChanged"
         Text="{Binding MyText, Mode=TwoWay,
                UpdateSourceTrigger=Explicit}" />

UpdateSourceTrigger = Explicit is a smart bonus here. What is it? Explicit: Updates the binding source only when you call the UpdateSource method. It saves you one extra binding set when the user leaves the TextBox.

In C#:

private void OnTextBoxTextChanged( object sender, TextChangedEventArgs e )
{
  TextBox textBox = sender as TextBox;
  // Update the binding source
  BindingExpression bindingExpr = textBox.GetBindingExpression( TextBox.TextProperty );
  bindingExpr.UpdateSource();
}
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • Solved "The one specific" issue related to binding using the above "BindingExpression" code. Tons of thanks for making my code happy. – Jsinh Jan 11 '13 at 08:13
23

I like using an attached property. Just in case you're into those little buggers.

<toolkit:DataField Label="Name">
  <TextBox Text="{Binding Product.Name, Mode=TwoWay}" c:BindingUtility.UpdateSourceOnChange="True"/>
</toolkit:DataField>

And then the backing code.

public class BindingUtility
{
public static bool GetUpdateSourceOnChange(DependencyObject d)
{
  return (bool)d.GetValue(UpdateSourceOnChangeProperty);
}

public static void SetUpdateSourceOnChange(DependencyObject d, bool value)
{
  d.SetValue(UpdateSourceOnChangeProperty, value);
}

// Using a DependencyProperty as the backing store for …
public static readonly DependencyProperty
  UpdateSourceOnChangeProperty =
    DependencyProperty.RegisterAttached(
    "UpdateSourceOnChange",
    typeof(bool),
              typeof(BindingUtility),
    new PropertyMetadata(false, OnPropertyChanged));

private static void OnPropertyChanged (DependencyObject d,
  DependencyPropertyChangedEventArgs e)
{
  var textBox = d as TextBox;
  if (textBox == null)
    return;
  if ((bool)e.NewValue)
  {
    textBox.TextChanged += OnTextChanged;
  }
  else
  {
    textBox.TextChanged -= OnTextChanged;
  }
}
static void OnTextChanged(object s, TextChangedEventArgs e)
{
  var textBox = s as TextBox;
  if (textBox == null)
    return;

  var bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty);
  if (bindingExpression != null)
  {
    bindingExpression.UpdateSource();
  }
}
}
Parrhesia Joe
  • 1,327
  • 12
  • 12
  • 1
    Be careful using this technique, it can introduce Memory Leaks as the event handler is never deregistered. http://sharpfellows.com/post/Memory-Leaks-and-Dependency-Properties.aspx – Flatliner DOA Feb 08 '14 at 10:34
  • @FlatlinerDOA : In this case there is no risk of memory leak because the reference is from the non-static object (TextBox) to the static event handler (BindingUtility.OnTextChanged). The problem would have been if the reference was the other way around. – Andrei Rînea Apr 01 '14 at 15:11
  • @Parrhesia Joe , i have attached behavior in most of my toolkit text-box, In a textbox i have used `` this has some issues , seems like cursor goes to first item when i press 0 – Eldho May 25 '15 at 18:21
5

Not through binding syntax, no, but it's easy enough without. You have to handle the TextChanged event and call UpdateSource on the binding.

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    ((TextBox) sender).GetBindingExpression( TextBox.TextProperty ).UpdateSource();
}

This can be converted into an attached behavior as well pretty easily.

Adam Sills
  • 16,896
  • 6
  • 51
  • 56
1

You can write your own TextBox Behavior to handle Update on TextChanged:

This is my sample to PasswordBox but you can simple change it to handle any property of the any object.

public class UpdateSourceOnPasswordChangedBehavior
     : Behavior<PasswordBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PasswordChanged += OnPasswordChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PasswordChanged -= OnPasswordChanged;
    }

    private void OnPasswordChanged(object sender, RoutedEventArgs e)
    {
        AssociatedObject.GetBindingExpression(PasswordBox.PasswordProperty).UpdateSource();
    }
}

Ussage:

<PasswordBox x:Name="Password" Password="{Binding Password, Mode=TwoWay}" >
    <i:Interaction.Behaviors>
        <common:UpdateSourceOnPasswordChangedBehavior/>
    </i:Interaction.Behaviors>
</PasswordBox>
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Viacheslav Smityukh
  • 5,652
  • 4
  • 24
  • 42
1

In TextChanged event call UpdateSource().

BindingExpression be = itemNameTextBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
Lukasz Madon
  • 14,664
  • 14
  • 64
  • 108
0

UpdateSourceTrigger=Explicit doesnt work for me, hence Im using custom class derivated from TextBox

public class TextBoxEx : TextBox
{
    public TextBoxEx()
    {
        TextChanged += (sender, args) =>
                           {
                               var bindingExpression = GetBindingExpression(TextProperty);
                               if (bindingExpression != null)
                               {
                                   bindingExpression.UpdateSource();
                               }
                           };
    }

}
vmachacek
  • 530
  • 1
  • 11
  • 27
0

It's just one line of code!

(sender as TextBox).GetBindingExpression(TextBox.TextProperty).UpdateSource();

You can create a generic TextChanged event (for example "ImmediateTextBox_TextChanged") in the code behind of your page, and than link it to any TextBox in the page.

MAXE
  • 4,978
  • 2
  • 45
  • 61
0

I took Praetorian's answer and made an extension class that inherits TextBox so you don't have to muddle up your view's code behind with this behavior.

C-Sharp:

public class TextBoxUpdate : TextBox
{
    public TextBoxUpdate()
    {
        TextChanged += OnTextBoxTextChanged;
    }
    private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox senderText = (TextBox)sender;
        BindingExpression bindingExp = senderText.GetBindingExpression(TextBox.TextProperty);
        bindingExp.UpdateSource();
    }
}

VisualBasic:

Public Class TextBoxUpdate : Inherits TextBox

    Private Sub OnTextBoxTextChanged(sender As Object, e As TextChangedEventArgs) Handles Me.TextChanged
        Dim senderText As TextBox = DirectCast(sender, TextBox)
        Dim bindingExp As BindingExpression = senderText.GetBindingExpression(TextBox.TextProperty)
        bindingExp.UpdateSource()
    End Sub

End Class

Then call like this in XAML:

<local:TextBoxUpdate Text="{Binding PersonName, Mode=TwoWay}"/>
Community
  • 1
  • 1
KyleMit
  • 30,350
  • 66
  • 462
  • 664