bestsource

WPF: TextBox에서 포커스를 프로그래밍 방식으로 삭제하는 방법

bestsource 2023. 4. 19. 23:19
반응형

WPF: TextBox에서 포커스를 프로그래밍 방식으로 삭제하는 방법

WPF에 간단한 동작(적어도 그렇다고 생각했다)을 추가하고 싶다.TextBox.

사용자가 Escape를 누를 때 나는 다음 명령을 원한다.TextBox그는 사용자가 편집을 시작했을 때 가지고 있던 텍스트를 가지기 위해 편집하고 있으며, 나는 포커스를 편집에서 제거하고 싶다.TextBox.

편집의 선두에 있는 값으로 텍스트를 설정하는 것은 문제 없습니다.

문제는 요소의 포커스를 제거하는 것입니다.포커스를 다른 컴포넌트로 옮기고 싶지 않습니다.그냥 다른 컴포넌트로 옮겨서TextBox집중력을 잃었어요.초점을 맞추려면 보이지 않는 요소가 있어야 하나요?TextBox집중력을 잃을 수 있나요?

.NET Framework 4에서만

사용하고 있는 코드:

// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)textBox.Parent;
while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
{
    parent = (FrameworkElement)parent.Parent;
}

DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);

위의 답변 중 어느 것도 나에게는 효과가 없고, 받아들여진 답변은 키보드 포커스에 대해서만 기능하기 때문에 다음과 같은 접근방식을 취했습니다.

// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();

논리적으로나 키보드에 초점을 맞춘 두 가지를 모두 죽입니다.

파티에는 조금 늦었지만, 도움이 되었기 때문에 갑니다.

.Net 3.0 이후FrameworkElementMoveFocus 기능이 있어서 도움이 됐어요.

포커스를 포커스 가능한 상위 항목으로 설정할 수 있습니다.이 코드는 텍스트 상자가 템플릿 내에 있고 동일한 템플릿 내에 포커스가 있는 상위 항목이 없는 경우에도 작동합니다.

DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
    var element = ancestor as UIElement;
    if (element != null && element.Focusable)
    {
        element.Focus();
        break;
    }

    ancestor = VisualTreeHelper.GetParent(ancestor);
}

AFAIK, 포커스를 완전히 제거할 수 없습니다.창에 있는 무언가가 항상 포커스를 가집니다.

특히 LostFocus 바인딩을 사용할 때는 매우 까다롭습니다.다만, 회피책은, 빈 라벨을 추가하고, 거기에 초점을 맞추는 것입니다.

<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />

...

OnKeyDown(object sender, RoutedEventArgs e)
{
  //if is Esc
  ResetFocusArea.Focus();
}

LPL의 답변을 사용하는 것이 효과적이지만 드롭다운 메뉴에서 옵션을 선택할 수 없게 됩니다.이 문제를 해결하기 위해 초점 요소가 텍스트 상자인지 확인하기 위해 체크를 추가했습니다.

Enter 키를 눌렀을 때와 같은 체크를 하면 최종 코드는 다음과 같습니다.

    public Menu()
    {
        InitializeComponent();
        this.PreviewMouseDown += PreviewMouseDownEventHandler;
        this.KeyDown += WindowKeyDownHandler;
    }
    void ClearFocus()
    {
        UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
        if (elementWithFocus is System.Windows.Controls.TextBox tb)
        {
            if (Keyboard.FocusedElement != null)
            {
                Keyboard.FocusedElement.RaiseEvent(new RoutedEventArgs(UIElement.LostFocusEvent));
                Keyboard.ClearFocus();
            }
        }
    }

    private void PreviewMouseDownEventHandler(object sender, MouseButtonEventArgs e)
    {
        ClearFocus();
    }
    private void WindowKeyDownHandler(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            ClearFocus();
        }
    }

이것에 의해, 모든 텍스트 박스에 포커스를 추가할 필요가 없어져, 프로그램의 다른 부분과의 호환성을 해치지 않고, 다른 요소로 간단하게 확장할 수 있습니다.

Windows Phone Development에서 저는 방금Focus()또는this.Focus()PhoneApplicationPage에 접속하면 마법처럼 작동합니다.

제 답변이 위의 질문을 직접적으로 다루지는 않지만, 그 문구가 프로그래밍 방식으로 초점을 없애는 것에 대한 "질문"이 된 것 같습니다.이것이 필요한 일반적인 시나리오는 사용자가 창과 같이 루트 컨트롤의 배경을 좌클릭할 때 포커스를 지울 수 있다는 것입니다.

이를 위해 Attached Behavior를 생성하여 동적으로 작성된 컨트롤(이 경우 빈 라벨)로 포커스를 전환할 수 있습니다.더미 라벨을 추가할 수 있는 패널을 찾기 위해 하위 요소에서 반복되므로 창과 같은 최상위 요소에서 이 동작을 사용하는 것이 좋습니다.

public class LoseFocusOnLeftClick : Behavior<FrameworkElement>
{
    private readonly MouseBinding _leftClick;
    private readonly Label _emptyControl = new Label() { Focusable = true, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top };

    public LoseFocusOnLeftClick()
    {
        _leftClick = new MouseBinding(new RelayCommand(LoseFocus), new MouseGesture(MouseAction.LeftClick));
    }

    protected override void OnAttached()
    {
        AssociatedObject.InputBindings.Add(_leftClick);
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }        

    protected override void OnDetaching()
    {
        AssociatedObject.InputBindings.Remove(_leftClick);
        AssociatedObject.Loaded -= AssociatedObject_Loaded;
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        AssociatedObject.Loaded -= AssociatedObject_Loaded;

        AttachEmptyControl();
    }

    private void AttachEmptyControl()
    {            
        DependencyObject currentElement = AssociatedObject;
        while (!(currentElement is Panel))
        {
            currentElement = VisualTreeHelper.GetChild(currentElement, 0);
        }

        ((Panel)currentElement).Children.Add(_emptyControl);
    }

    private void LoseFocus()
    {            
        _emptyControl.Focus();
    }
}

특정 텍스트 상자에서 포커스를 제거하려면 이 줄을 추가하십시오.

textBox.Focusable = false;

언급URL : https://stackoverflow.com/questions/2914495/wpf-how-to-programmatically-remove-focus-from-a-textbox

반응형