[c#] Enter 키를 누를 때 TextBox 바인딩

기본 데이터 바인딩은 TextBox이며 다음 TwoWay과 같은 경우에만 속성에 텍스트를 커밋합니다.TextBox 포커스를 잃은 .

?의 Enter키를 누를 때 데이터 바인딩을 수행하는 쉬운 XAML 방법 이 TextBox있습니까? 뒤에있는 코드에서하는 것이 꽤 쉽다는 것을 알고 있지만 이것이 TextBox복잡한 내부에 있다고 상상해보십시오 DataTemplate.



답변

연결된 동작 을 만들어 순수한 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"/>

(InputBindingsManager를 넣은 네임 스페이스를 가리키는 XAML 파일의 루트 요소에 “b”에 대한 xmlns clr-namespace 참조를 포함해야합니다).


답변

이것이 제가이 문제를 해결 한 방법입니다. 코드 뒤에있는 특수 이벤트 핸들러를 만들었습니다.

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에서 작동해야합니다. 이제이 하나의 이벤트 핸들러를이 기능이 필요한 모든 텍스트 상자에 추가 할 수 있습니다.


답변

설명하는 작업을 수행하는 “순수한 XAML”방법이 있다고 생각하지 않습니다. 다음 과 같이 UpdateSourceTrigger 속성 을 설정하여 TextBox의 텍스트가 변경 될 때마다 (TextBox가 포커스를 잃을 때가 아니라) 업데이트되도록 바인딩을 설정할 수 있습니다 .

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

UpdateSourceTrigger를 “Explicit”로 설정 한 다음 TextBox의 PreviewKeyDown 이벤트 (Enter 키 찾기)를 처리하면 원하는 것을 얻을 수 있지만 코드 숨김이 필요합니다. 아마도 일종의 연결된 속성 (내 EnterKeyTraversal 속성 과 유사 )이 당신을 위해 작동 할 것입니다.


답변

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}" />


답변

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.

이렇게하면 다음 Command과 같이 보입니다 ( DelegateCommandVM에서 스타일 구현을 사용하는 경우 ).

    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코드 숨김에있는 모든 코드에 사용할 수 있지만 System.Windows.ControlsVM 에 종속성이 없도록 자체 클래스에 넣을 수 있습니다 . 코드 지침이 얼마나 엄격한 지에 따라 다릅니다.


답변

다음은 나에게 매우 간단하고 AttachedBehaviour를 추가하는 것보다 더 쉬운 접근 방식입니다 (유효한 솔루션이기도합니다). 기본 UpdateSourceTrigger (TextBox의 경우 LostFocus)를 사용한 다음 명령에 바인딩 된 Enter 키에 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는 Property에 바인딩됩니다.

 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 이벤트를 포착합니다.


답변

이것은 원래 질문에 대한 답변이 아니라 @Samuel Jack 이 수락 한 답변 의 확장입니다 . 나는 내 자신의 응용 프로그램에서 다음을 수행했으며 Samuel의 솔루션의 우아함에 경외심을 느꼈습니다. 그것은 매우 깨끗하고 재사용이 가능합니다.TextBox . 커뮤니티와 공유해야한다고 생각했습니다.

TextBoxesEnter시 바인딩 소스를 업데이트하는 데 필요한 천 개의 창이있는 경우 Window Resources각 TextBox에 연결하는 대신 아래 XAML을 포함하여이 동작을 모든 항목에 연결할 수 있습니다 . 먼저 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를 포함하는 Window 자식 요소 중 하나의 리소스 (예 : a )에 스타일을 넣어 범위를 제한 할 수 있습니다 .