代码之家  ›  专栏  ›  技术社区  ›  Jobi Joy

按Enter键时绑定文本框

  •  97
  • Jobi Joy  · 技术社区  · 16 年前

    上的默认数据绑定 TextBox TwoWay 只有当 文本框 失去了焦点

    当我按下 进入 关键在 文本框 ?.我知道在代码背后很容易做到,但是想象一下 文本框 在某个复杂的内部 DataTemplate .

    12 回复  |  直到 6 年前
        1
  •  128
  •   Grhm    9 年前

    通过创建一个 attached behaviour .

    像这样:

    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 属性设置为当 进入 按键。这样地

    <TextBox Name="itemNameTextBox"
             Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}"
             b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"/>
    

    (您只需确保在XAML文件的根元素中包含“b”的xmlns clr命名空间引用,指向您将inputBindingsManager放入的任何命名空间)。

        2
  •  46
  •   Matt Hamilton    16 年前

    我不相信有任何“纯XAML”方法可以实现您所描述的。通过设置 UpdateSourceTrigger 属性,如下所示:

    <TextBox Name="itemNameTextBox"
        Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}" />
    

    如果将updateSourceTrigger设置为“explicit”,然后处理文本框的PreviewKeyDown事件(查找Enter键),则可以实现所需的功能,但它需要代码隐藏。可能是某种附属财产(类似于 EnterKeyTraversal 属性)我可以为您工作。

        3
  •  35
  •   Ben    12 年前

    这就是我解决这个问题的方法。我创建了一个特殊的事件处理程序,它进入了代码的后面:

    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 引用以使它自己的绑定得到更新。因为事件处理程序是独立的,所以它应该在复杂的数据模板中工作。现在可以将此事件处理程序添加到所有需要此功能的文本框中。

        4
  •  25
  •   Ryan Versaw    15 年前

    您可以轻松地创建继承自文本框的自己的控件,并在整个项目中重用它。

    与此类似的东西应该可以工作:

    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}" />
    
        5
  •  11
  •   toadflakz    10 年前

    如果将Ben和Ausadmin的解决方案结合起来,最终会得到一个非常适合MVVM的解决方案:

    <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 自身作为参数 Command .

    这会导致 命令 看起来像这样(如果你用的是 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();
            }
        }
    

    这个 命令 实现可用于任何 文本框 最好的是,代码后面没有代码,尽管您可能希望将它放在自己的类中,这样就不依赖于 System.Windows.Controls 在你的虚拟机中。这取决于您的代码准则有多严格。

        6
  •  4
  •   ausadmin    12 年前

    这里有一种方法,对我来说似乎非常简单,而且更容易添加附加的行为(这也是一个有效的解决方案)。我们使用默认的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
    

    文本框绑定到属性

     Public Property Txt1 As String
        Get
            Return _txt1
        End Get
        Set(value As String)
            _txt1 = value
            OnPropertyChanged("Txt1")
        End Set
    End Property
    

    到目前为止,这似乎工作得很好,并在文本框中捕获了Enter键事件。

        7
  •  3
  •   Mr.Pidra    10 年前

    更简单,只需设置 UpdateSourceTrigger PropertyChanged 在你 TextBox 的绑定而不在codebehind中添加任何内容。 就像这样:

    <TextBox Text="{Binding Path=BoundProperty, UpdateSourceTrigger=PropertyChanged}"/>
    

    它对我有用。

        8
  •  3
  •   Nik    7 年前

    这不是原始问题的答案,而是 accepted answer 作者:塞缪尔·杰克。我在自己的应用程序中做了以下操作,对塞缪尔的解决方案的优雅感到敬畏。它非常干净,而且非常可重用,因为它可以用于任何控件,而不仅仅是 TextBox . 我认为这应该和社区分享。

    如果你有一扇有一千个窗户 TextBoxes 所有这些都需要在Enter上更新绑定源,您可以通过将下面的XAML包含到 Window Resources 而不是将其附加到每个文本框。首先,必须根据 Samuel's post 当然。

    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
            <Style.Setters>
                <Setter Property="b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed" Value="TextBox.Text"/>
            </Style.Setters>
        </Style>
    </Window.Resources>
    

    如果需要,您可以通过将样式放入窗口的一个子元素(即 Grid )包含目标文本框的。

        9
  •  2
  •   akjoshi HCP    13 年前

    如果在文本框中使用多绑定,则需要使用 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();
         }
    }
    
        10
  •  2
  •   Valery    8 年前

    这对我很有用:

            <TextBox                 
                Text="{Binding Path=UserInput, UpdateSourceTrigger=PropertyChanged}">
                <TextBox.InputBindings>
                    <KeyBinding Key="Return" 
                                Command="{Binding Ok}"/>
                </TextBox.InputBindings>
            </TextBox>
    
        11
  •  1
  •   Community CDub    7 年前

    这里的回答相当优雅,使用附加的行为,我的首选方法几乎任何东西。

    WPF how to make textbox lose focus after hitting enter

        12
  •  0
  •   metoyou    6 年前

    我个人认为拥有标记扩展是一种更清洁的方法。

    public class UpdatePropertySourceWhenEnterPressedExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return new DelegateCommand<TextBox>(textbox => textbox.GetBindingExpression(TextBox.TextProperty).UpdateSource());
        }
    }
    


    <TextBox x:Name="TextBox"
                 Text="{Binding Text}">
            <TextBox.InputBindings>
                <KeyBinding Key="Enter"
                            Command="{markupExtensions:UpdatePropertySourceWhenEnterPressed}" 
                            CommandParameter="{Binding ElementName=TextBox}"/>
            </TextBox.InputBindings>
    </TextBox>