[wpf] WPF 및 초기 초점

WPF 응용 프로그램이 시작될 때 포커스가없는 것 같습니다.

정말 이상합니다. 내가 사용한 다른 모든 프레임 워크는 예상 한대로 수행합니다. 첫 번째 컨트롤에 첫 번째 컨트롤을 탭 순서로 둡니다. 그러나 나는 그것이 내 응용 프로그램뿐만 아니라 WPF임을 확인했습니다. 새 창을 만들고 TextBox를 넣고 응용 프로그램을 실행하면 TextBox는 클릭하거나 Tab 키를 누를 때까지 포커스가 없습니다. . 왝.

내 실제 응용 프로그램은 TextBox보다 더 복잡합니다. UserControls 내에 여러 계층의 UserControl이 있습니다. 이러한 UserControl 중 하나에 Focusable = “True”및 KeyDown / KeyUp 핸들러가 있으며, 창이 열리 자마자 포커스를 갖기를 원합니다. 그래도 여전히 WPF 초보자이지만, 이것을하는 방법을 알아내는 데 많은 운이 없습니다.

앱을 시작하고 Tab 키를 누르면 포커스가 포커스 가능한 컨트롤로 이동하여 원하는 방식으로 작동하기 시작합니다. 그러나 사용자가 창을 사용하기 전에 Tab 키를 누르지 않기를 바랍니다.

FocusManager.FocusedElement를 가지고 놀았지만 컨트롤을 설정할 컨트롤 (최상위 Window 창, 포커스 가능한 컨트롤을 포함하는 부모, 포커스 가능한 컨트롤 자체) 또는 무엇을 설정할지 잘 모르겠습니다.

창을 열 자마자 깊게 중첩 된 컨트롤이 초기 초점을 갖도록하려면 어떻게해야합니까? 또는 탭 순서에서 첫 번째 포커스 가능한 컨트롤에 초점을 맞추는 것이 더 낫습니까?



답변

이것도 작동합니다.

<Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">

   <DataGrid x:Name="SomeElement">
     ...
   </DataGrid>
</Window>


답변

Focusable 속성이 사용되는 위치를 확인하기 위해 Reflector를 파헤 치고이 솔루션으로가는 길을 찾았습니다. 내 창 생성자에 다음 코드를 추가하면됩니다.

Loaded += (sender, e) =>
    MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

이것은 탭 순서에서 첫 번째 컨트롤을 자동으로 선택하므로 모든 창과 Just Work에 놓을 수있는 일반적인 솔루션입니다.


답변

첨부 된 동작으로 구현 된 허용 된 답변을 기반으로합니다 .

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace UI.Behaviors
{
    public static class FocusBehavior
    {
        public static readonly DependencyProperty FocusFirstProperty =
            DependencyProperty.RegisterAttached(
                "FocusFirst",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, OnFocusFirstPropertyChanged));

        public static bool GetFocusFirst(Control control)
        {
            return (bool)control.GetValue(FocusFirstProperty);
        }

        public static void SetFocusFirst (Control control, bool value)
        {
            control.SetValue(FocusFirstProperty, value);
        }

        static void OnFocusFirstPropertyChanged(
            DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Control control = obj as Control;
            if (control == null || !(args.NewValue is bool))
            {
                return;
            }

            if ((bool)args.NewValue)
            {
                control.Loaded += (sender, e) =>
                    control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
        }
    }
}

다음과 같이 사용하십시오.

<Window xmlns:Behaviors="clr-namespace:UI.Behaviors"
        Behaviors:FocusBehavior.FocusFirst="true">


답변

다른 가능한 해결책을 찾았습니다. Mark Smith는 FocusManager.FocusedElement와 함께 사용할 FirstFocusedElement 태그 확장 을 게시했습니다 .

<UserControl x:Class="FocusTest.Page2"
    xmlns:FocusTest="clr-namespace:FocusTest"
    FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">


답변

동일한 문제로 간단한 해결책으로 해결했습니다. 메인 창에서 :

  <Window ....
        FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}"
         ... />

사용자 컨트롤에서 :

private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
        {
            targetcontrol.Focus();
            this.GotFocus -= UserControl_GotFocus_1;  // to set focus only once
        }


답변

‘WPF 초기 초점 악몽’을 겪고 스택에 대한 답변을 바탕으로 다음이 가장 좋은 솔루션임을 입증했습니다.

먼저 App.xaml OnStartup ()을 다음과 같이 추가하십시오.

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
          new RoutedEventHandler(WindowLoaded));

그런 다음 App.xaml에도 ‘WindowLoaded’이벤트를 추가하십시오.

void WindowLoaded(object sender, RoutedEventArgs e)
    {
        var window = e.Source as Window;
        System.Threading.Thread.Sleep(100);
        window.Dispatcher.Invoke(
        new Action(() =>
        {
            window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

        }));
    }

일부 프레임 워크 경쟁 조건으로 인해 WPF 초기 초점이 대부분 실패하므로 스레딩 문제를 사용해야합니다.

전체 앱에 대해 전 세계적으로 사용되는 다음 솔루션을 가장 잘 찾았습니다.

그것이 도움이되기를 바랍니다 …

오란


답변

XAML에서 컨트롤 자체를 포커스 된 요소로 쉽게 설정할 수 있습니다.

<Window>
   <DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
     ...
   </DataGrid>
</Window>

나는 이것을 usercontrol에서 설정하고 이것이 작동하는지 보지 않았지만 그것이 가능할 수도 있습니다.