Bind TextBox on Enter-key press
Solution 1
You can make yourself a pure XAML approach by creating an attached behaviour.
Something like this:
public static class InputBindingsManager
{
public static readonly DependencyProperty UpdatePropertySourceWhenEnterPressedProperty = DependencyProperty.RegisterAttached(
"UpdatePropertySourceWhenEnterPressed", typeof(DependencyProperty), typeof(InputBindingsManager), new PropertyMetadata(null, OnUpdatePropertySourceWhenEnterPressedPropertyChanged));
static InputBindingsManager()
{
}
public static void SetUpdatePropertySourceWhenEnterPressed(DependencyObject dp, DependencyProperty value)
{
dp.SetValue(UpdatePropertySourceWhenEnterPressedProperty, value);
}
public static DependencyProperty GetUpdatePropertySourceWhenEnterPressed(DependencyObject dp)
{
return (DependencyProperty)dp.GetValue(UpdatePropertySourceWhenEnterPressedProperty);
}
private static void OnUpdatePropertySourceWhenEnterPressedPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
UIElement element = dp as UIElement;
if (element == null)
{
return;
}
if (e.OldValue != null)
{
element.PreviewKeyDown -= HandlePreviewKeyDown;
}
if (e.NewValue != null)
{
element.PreviewKeyDown += new KeyEventHandler(HandlePreviewKeyDown);
}
}
static void HandlePreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
DoUpdateSource(e.Source);
}
}
static void DoUpdateSource(object source)
{
DependencyProperty property =
GetUpdatePropertySourceWhenEnterPressed(source as DependencyObject);
if (property == null)
{
return;
}
UIElement elt = source as UIElement;
if (elt == null)
{
return;
}
BindingExpression binding = BindingOperations.GetBindingExpression(elt, property);
if (binding != null)
{
binding.UpdateSource();
}
}
}
Then in your XAML you set the InputBindingsManager.UpdatePropertySourceWhenEnterPressedProperty
property to the one you want updating when the Enter key is pressed. Like this
<TextBox Name="itemNameTextBox"
Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}"
b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"/>
(You just need to make sure to include an xmlns clr-namespace reference for "b" in the root element of your XAML file pointing to which ever namespace you put the InputBindingsManager in).
Solution 2
This is how I solved this problem. I created a special event handler that went into the code behind:
private void TextBox_KeyEnterUpdate(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
TextBox tBox = (TextBox)sender;
DependencyProperty prop = TextBox.TextProperty;
BindingExpression binding = BindingOperations.GetBindingExpression(tBox, prop);
if (binding != null) { binding.UpdateSource(); }
}
}
Then I just added this as a KeyUp event handler in the XAML:
<TextBox Text="{Binding TextValue1}" KeyUp="TextBox_KeyEnterUpdate" />
<TextBox Text="{Binding TextValue2}" KeyUp="TextBox_KeyEnterUpdate" />
The event handler uses its sender
reference to cause it's own binding to get updated. Since the event handler is self-contained then it should work in a complex DataTemplate. This one event handler can now be added to all the textboxes that need this feature.
Solution 3
I don't believe that there's any "pure XAML" way to do what you're describing. You can set up a binding so that it updates whenever the text in a TextBox changes (rather than when the TextBox loses focus) by setting the UpdateSourceTrigger property, like this:
<TextBox Name="itemNameTextBox"
Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}" />
If you set UpdateSourceTrigger to "Explicit" and then handled the TextBox's PreviewKeyDown event (looking for the Enter key) then you could achieve what you want, but it would require code-behind. Perhaps some sort of attached property (similar to my EnterKeyTraversal property) woudld work for you.
Solution 4
You could easily create your own control inheriting from TextBox and reuse it throughout your project.
Something similar to this should work:
public class SubmitTextBox : TextBox
{
public SubmitTextBox()
: base()
{
PreviewKeyDown += new KeyEventHandler(SubmitTextBox_PreviewKeyDown);
}
void SubmitTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
BindingExpression be = GetBindingExpression(TextBox.TextProperty);
if (be != null)
{
be.UpdateSource();
}
}
}
}
There may be a way to get around this step, but otherwise you should bind like this (using Explicit):
<custom:SubmitTextBox
Text="{Binding Path=BoundProperty, UpdateSourceTrigger=Explicit}" />
Solution 5
If you combine both Ben and ausadmin's solutions, you end up with a very MVVM friendly solution:
<TextBox Text="{Binding Txt1, Mode=TwoWay, UpdateSourceTrigger=Explicit}">
<TextBox.InputBindings>
<KeyBinding Gesture="Enter"
Command="{Binding UpdateTextBoxBindingOnEnterCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}" />
</TextBox.InputBindings>
</TextBox>
...which means you are passing the TextBox
itself as the parameter to the Command
.
This leads to your Command
looking like this (if you're using a DelegateCommand
-style implementation in your VM):
public bool CanExecuteUpdateTextBoxBindingOnEnterCommand(object parameter)
{
return true;
}
public void ExecuteUpdateTextBoxBindingOnEnterCommand(object parameter)
{
TextBox tBox = parameter as TextBox;
if (tBox != null)
{
DependencyProperty prop = TextBox.TextProperty;
BindingExpression binding = BindingOperations.GetBindingExpression(tBox, prop);
if (binding != null)
binding.UpdateSource();
}
}
This Command
implementation can be used for any TextBox
and best of all no code in the code-behind though you may want to put this in it's own class so there are no dependencies on System.Windows.Controls
in your VM. It depends on how strict your code guidelines are.
Related videos on Youtube
Jobi Joy
VP of Engineering www.identitymine.com We build experiences on all platforms #Windows #Xbox #Windows10 #HTML #WPF #XAML #WinUI #xamarin (iOS and Android)
Updated on July 08, 2022Comments
-
Jobi Joy almost 2 years
The default databinding on
TextBox
isTwoWay
and it commits the text to the property only whenTextBox
lost its focus.Is there any easy XAML way to make the databinding happen when I press the Enter key on the
TextBox
?. I know it is pretty easy to do in the code behind, but imagine if thisTextBox
is inside some complexDataTemplate
. -
Mikhail Poda over 12 yearsIn WPF/Silverlight you should never use inheritance - it messes styles and is not as flexible as Attached Behaviors. For example with Attached Behaviors you can have both Watermark and UpdateOnEnter on the same textbox.
-
Syaiful Nizam Yahya over 11 yearsi tried <TextBox x:Name="itemNameTextBox" Text="{Binding Source, ElementName=webBrowserCustom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"/> but it seems webbrowser doesnt update its source. anything i missed? i didnt handle any event. i assume by binding 2 way, its auto handle event. am i wrong? thanks.
-
ihake almost 10 yearsIn an effort to save future readers a few minutes of fiddling, I just used this in my project, and the sample XAML provided above didn't work right. The source was updated on every character change. Changing "UpdateSourceTrigger=PropertyChanged" to "UpdateSourceTrigger=Explicit" fixed the issue. Now it all works as desired.
-
VoteCoffee over 9 years@ihake: I think your recommended change will also prevent updating on focus lost though
-
VoteCoffee over 9 yearsNice. Very clean. If a multibinding is involved, you may need to use BindingOperations.GetBindingExpressionBase(tBox, prop); and then binding.UpdateTarget();
-
j riv almost 9 yearsSomething tells me this is an underrated post. A lot of answers are popular because they are "XAML-y". But this one appears to save space in most occasions.
-
David Hollinshead almost 9 yearsUpdateSourceTrigger=PropertyChanged may be inconvenient when typing a real number. For example "3." causes a problem when bound to a float. I'd recommend not specifying UpdateSourceTrigger (or setting to LostFocus) in addition to the attached behaviour. This gives the best of both worlds.
-
Jamin over 8 years+1 This also allows you to leave alone UpdateSourceTrigger in case you have already painstakingly got your TextBox bindings to already behave the way you want (with styles, validation, twoway, etc.), but currently just won't receive input after pressing Enter.
-
Nicholas Miller over 8 yearsExcellent work! Tiny nit-pick: When the
UpdatePropertySourceWhenEnterPressed
changes from a valid value to a different valid value, you are unsubscribing & re-subscribing to thePreviewKeyDown
event unnecessarily. Instead, all you should need is to check whether or not thee.NewValue
isnull
or not. If notnull
, then subscribe; otherwise, ifnull
, then unsubscribe. -
Nicholas Miller over 8 yearsAnother thing, I've noticed that calling
binding.UpdateSource()
clears validation errors. I needed to check first if the update should occur by looking atBindingExpression.HasError
. -
sth_Weird over 8 yearsThis answer may be simpler than the one marked as answer, but it has some limitations. Image you want to do some kind of check in the set-function of the bound property (checking if the input is valid). You do not want to call that check function after every key the user pressed, do you (especially not when the function takes some time).?
-
Oystein over 6 yearsThis is the cleanest approach that I've found, and in my opinion should be marked as the answer. Added an additional null check on sender, a check on Key.Return (Enter key on my keyboard returns Key.Return), and Keyboard.ClearFocus() to remove focus from the TextBox after updating the source property. I've made edits to the answer that's awaiting peer review.
-
Nik about 6 yearsI love this solution, thanks for posting it! For anyone who needs to attach this behaviour to numerous TextBoxes in your application, I posted an extension to this answer on how you can achieve that very easily. See the post here
-
Allender about 5 yearsAgree with comments above. But for me KeyDown event was more appropriate
-
CAD bloke almost 5 yearsI used
KeyBinding
in the XAML to fire this method because my UI has a "Default" control that catches the enter key. You need to catch it within this TextBox to stop it propagating up the UI tree to the "Default" control. -
Ben almost 5 yearsNOTE for UWP projects: the binding has be obtained from the textbox itself,
tBox.GetBindingExpression(props)
because for some reason they left out the static method. -
hfann over 3 yearsThis works well in a dialog situation when a button has
IsDefault
property set to true. -
Joe over 3 yearsThis could also be even simpler if you had a default style for TextBox with an EventSetter that directed all KeyUp events (or KeyDown if you prefer) to the handler that's listed. If the style were in a ResourceDictionary, you could just make some code-behind for the dictionary. Then you would not even need to specify the KeyUp/KeyDown handler on each TextBox