[c#] 在Enter鍵按下時綁定TextBox



Answers

我不相信有任何“純粹的XAML”方式來完成你所描述的內容。 您可以設置一個綁定,以便通過設置UpdateSourceTrigger屬性來更新每當TextBox中的文本發生更改(而不是在TextBox失去焦點時)的綁定,如下所示:

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

如果您將UpdateSourceTrigger設置為“Explicit”,然後處理TextBox的PreviewKeyDown事件(查找Enter鍵),那麼您可以實現您想要的,但它需要代碼隱藏。 也許某種附加屬性(類似於我的EnterKeyTraversal屬性)woudld適合你。

Question

TextBox上的默認數據綁定是TwoWay ,它僅在TextBox失去焦點時才將文本提交給屬性。

當按下TextBox上的Enter鍵時,是否有任何簡單的XAML方法可以使數據綁定發生? 我知道在後面的代碼中很容易做到,但想像一下,如果這個TextBox是在一些複雜的DataTemplate




我個人認為有一個標記擴展是一個更清潔的方法。

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>



這不是對原始問題的回答,而是@Samuel Jack 接受的答案的延伸。 我在自己的應用程序中做了以下事情,並對Samuel解決方案的優雅感到敬畏。 它非常乾淨,非常可重用,因為它可以在任何控件上使用,而不僅僅是TextBox 。 我認為這應該與社區分享。

如果您有一個帶有一千個文本框的Window ,都需要在輸入時更新綁定源,那麼您可以通過將下面的XAML包括到您的Window Resources而不是將它附加到每個文本框來將此行為附加到所有這些文本框。 首先,您必須按照Samuel的帖子實施所附的行為,當然。

<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 )之一的資源中。




您可以輕鬆地創建自己的控件,從TextBox繼承並在整個項目中重複使用它。

類似的東西應該​​可以工作:

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();
            }
        }
    }
}

可能有辦法繞過這一步,但否則你應該像這樣綁定(使用Explicit):

<custom:SubmitTextBox
    Text="{Binding Path=BoundProperty, UpdateSourceTrigger=Explicit}" />



這對我來說似乎相當簡單,而且更容易添加AttachedBehaviour(這也是一個有效的解決方案)。 我們使用默認的UpdateSourceTrigger(LostFocus for TextBox),然後向輸入鍵添加一個InputBinding,綁定到一個命令。

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

到目前為止,這似乎很好,並捕捉到TextBox中的Enter Key事件。




如果您在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();
     }
}



Related