绑定input键上的文本框
TextBox
上的默认数据绑定是TwoWay
,只有当TextBox
失去焦点时,它才会将文本提交给属性。
当我按下TextBox
上的Enter键时,是否有任何简单的XAML方法可以使数据绑定发生? 我知道在后面的代码中执行起来很容易,但想象一下,如果这个TextBox
是在一些复杂的DataTemplate
里面的话。
您可以创build一个附加的行为,使自己成为一个纯粹的XAML方法。
像这样的东西:
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(); } } }
然后,在您的XAML中,将InputBindingsManager.UpdatePropertySourceWhenEnterPressedProperty
属性设置为按Enter键时要更新的属性。 喜欢这个
<TextBox Name="itemNameTextBox" Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}" b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"/>
(您只需确保在XAML文件的根元素中包含“b”的xmlns clr-名称空间引用,指向将InputBindingsManager放入哪个名称空间中)。
我不相信有任何“纯XAML”的方式来做你所描述的。 您可以设置一个绑定,以便通过设置UpdateSourceTrigger属性来更新每当TextBox中的文本发生更改(而不是在TextBox失去焦点时)的绑定,如下所示:
<TextBox Name="itemNameTextBox" Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}" />
如果您将UpdateSourceTrigger设置为“Explicit”,然后处理TextBox的PreviewKeyDown事件(查找Enter键),那么您可以实现所需的操作,但这需要代码隐藏。 也许某种附加属性(类似于我的EnterKeyTraversal属性)woudld适合你。
这就是我解决这个问题的方法。 我创build了一个特殊的事件处理程序,进入后面的代码:
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(); } } }
然后,我只是将其作为XAML中的KeyUp事件处理程序添加:
<TextBox Text="{Binding TextValue1}" KeyUp="TextBox_KeyEnterUpdate" /> <TextBox Text="{Binding TextValue2}" KeyUp="TextBox_KeyEnterUpdate" />
事件处理程序使用其sender
引用来使其自己的绑定得到更新。 由于事件处理程序是自包含的,因此它应该在复杂的DataTemplate中工作。 现在可以将这一个事件处理程序添加到所有需要此function的文本框中。
您可以轻松地创build自己的控件从TextBoxinheritance,并在整个项目中重复使用它。
类似的东西应该工作:
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(); } } } }
可能有办法绕过这一步,但否则你应该这样绑定(使用显式):
<custom:SubmitTextBox Text="{Binding Path=BoundProperty, UpdateSourceTrigger=Explicit}" />
如果您将Ben和ausadmin的解决scheme结合在一起,您将得到一个非常适合MVVM的解决scheme:
<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>
…这意味着您将TextBox
本身作为parameter passing给Command
。
这导致你的Command
看起来像这样(如果你在VM中使用DelegateCommand
风格的实现):
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(); } }
这个Command
实现可以用于任何TextBox
,最好在代码隐藏中没有代码,尽pipe你可能想把它放在它自己的类中,所以在你的虚拟机中没有System.Windows.Controls
依赖。 这取决于你的代码指南是多么严格。
这是一个对我来说似乎相当直接,更容易添加AttachedBehaviour(这也是一个有效的解决scheme)的方法。 我们使用默认的UpdateSourceTrigger(LostFocus for TextBox),然后将InputBinding添加到Enter键,绑定到一个命令。
xaml如下
<TextBox Grid.Row="0" Text="{Binding Txt1}" Height="30" Width="150"> <TextBox.InputBindings> <KeyBinding Gesture="Enter" Command="{Binding UpdateText1Command}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}},Path=Text}" /> </TextBox.InputBindings> </TextBox>
然后命令的方法是
Private Function CanExecuteUpdateText1(ByVal param As Object) As Boolean Return True End Function Private Sub ExecuteUpdateText1(ByVal param As Object) If TypeOf param Is String Then Txt1 = CType(param, String) End If End Sub
而TextBox绑定到属性
Public Property Txt1 As String Get Return _txt1 End Get Set(value As String) _txt1 = value OnPropertyChanged("Txt1") End Set End Property
到目前为止,这似乎工作得很好,捕捉到文本框中的Enter键事件。
更简单,只需在TextBox
的绑定中将UpdateSourceTrigger
设置为PropertyChanged
,而不需要在代码隐藏中添加任何内容。 像这样:
<TextBox Text="{Binding Path=BoundProperty, UpdateSourceTrigger=PropertyChanged}"/>
它适用于我。
如果您在您的TextBox中使用MultiBinding,则需要使用BindingOperations.GetMultiBindingExpression
方法而不是BindingOperations.GetBindingExpression
。
// Get the correct binding expression based on type of binding //(simple binding or multi binding. BindingExpressionBase binding = BindingOperations.GetBindingExpression(element, prop); if (binding == null) { binding = BindingOperations.GetMultiBindingExpression(element, prop); } if (binding != null) { object value = element.GetValue(prop); if (string.IsNullOrEmpty(value.ToString()) == true) { binding.UpdateTarget(); } else { binding.UpdateSource(); } }
这适用于我:
<TextBox Text="{Binding Path=UserInput, UpdateSourceTrigger=PropertyChanged}"> <TextBox.InputBindings> <KeyBinding Key="Return" Command="{Binding Ok}"/> </TextBox.InputBindings> </TextBox>
在这里使用附加的行为非常优雅地回答,我几乎任何东西的首选方法。
WPF如何使文本框input后失去焦点