Не могу установить фокус на дочерний элемент UserControl - PullRequest
38 голосов
/ 23 марта 2009

У меня есть UserControl, который содержит TextBox. Когда мое главное окно загружается, я хочу установить фокус на это текстовое поле, поэтому я добавил Focusable="True" GotFocus="UC_GotFocus" в определение UserControl s и FocusManager.FocusedElement="{Binding ElementName=login}" в определение основного окна. В методе UC_GotFocus я просто вызываю .Focus() на элементе управления, на котором хочу сосредоточиться, но это не работает.

Все, что мне нужно сделать, это иметь TextBox в фокусе UserControl получения при запуске приложения.

Любая помощь будет оценена, спасибо.

Ответы [ 18 ]

26 голосов
/ 08 мая 2009

Я недавно исправил эту проблему для заставки входа в систему, которая отображается через раскадровку при первой загрузке главного окна.

Я думаю, что для исправления было два ключа. Один из них заключался в том, чтобы сделать содержащий элемент фокусом. Другой должен был обработать событие Storyboard Completed для раскадровки, которая была вызвана загружаемым окном.

Эта раскадровка делает видимым холст имени пользователя и пароля, а затем становится на 100% непрозрачным. Ключевым моментом является то, что элемент управления именем пользователя не был виден до запуска раскадровки, и поэтому этот элемент управления не мог получить фокусировку клавиатура , пока он не был виден. На некоторое время меня оттолкнуло то, что он имел «фокус» (то есть фокус был верным, но, как оказалось, это был только логический фокус), и я не знал, что в WPF была концепция как логического, так и клавишного фокуса, пока не прочитал книгу Кента Бугаарта. ответ и глядя на WPF Microsoft текст ссылки

Как только я это сделал, решение моей конкретной проблемы было простым:

1) Сделать содержащий элемент фокусом

<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
    <TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
    </TextBox>
</Canvas>

2) Присоединить обработчик завершенных событий к раскадровке

    <Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>

и

3) Установите мое имя пользователя TextBox, чтобы в обработчике событий завершения раскадровки был фокус клавиатуры.

void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
 m_uxUsername.Focus();
}

Обратите внимание, что вызов item.Focus () приводит к вызову Keyboard.Focus (this), поэтому вам не нужно вызывать это явно. См. Этот вопрос о разнице между Keyboard.Focus (item) и item.Focus.

16 голосов
/ 03 декабря 2009

Это глупо, но работает:

Выведите поток, который ждет некоторое время, затем возвращается и устанавливает желаемый фокус. Он даже работает в контексте элемента host.

private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

 System.Threading.ThreadPool.QueueUserWorkItem(
                   (a) =>
                        {
                            System.Threading.Thread.Sleep(100);
                            someUiElementThatWantsFocus.Dispatcher.Invoke(
                            new Action(() =>
                            {
                                someUiElementThatWantsFocus.Focus();

                            }));
                        }
                   );

}
7 голосов
/ 23 марта 2009

Совсем недавно у меня был список, в котором размещались некоторые текстовые блоки. Я хотел иметь возможность дважды щелкнуть текстовый блок и превратить его в текстовое поле, затем сфокусироваться на нем и выделить весь текст, чтобы пользователь мог просто начать вводить новое имя (сродни Adobe Layers)

Во всяком случае, я делал это с событием, и оно просто не работало. Волшебная пуля для меня здесь была в том, чтобы убедиться, что я установил событие. Я полагаю, что было установкой фокуса, но как только событие пошло по пути, оно переключало логический фокус.

Мораль этой истории в том, что вы отмечаете событие как обработанное, это может быть вашей проблемой.

6 голосов
/ 06 августа 2010

«При установке начального фокуса при запуске приложения элемент для получения фокуса должен быть подключен к PresentationSource, а для элемента должны быть установлены значения Focusable и IsVisible, равные true. Рекомендуемое место для установки начального фокуса в обработчике событий Loaded "(MSDN)

Просто добавьте обработчик события «Loaded» в конструктор вашего окна (или элемента управления), и в этом обработчике вызова вызовите метод Focus () для целевого элемента управления.

    public MyWindow() {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
    }

    void MyWindow_Loaded(object sender, RoutedEventArgs e) {
        textBox.Focus();
    }
5 голосов
/ 20 сентября 2013

, поскольку я попробовал решение fuzquat и нашел его наиболее универсальным, я подумал, что поделюсь другой версией, поскольку некоторые жаловались на то, что оно выглядит грязным. так вот оно:

                casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
                {
                    x.Focus();
                }), DispatcherPriority.ApplicationIdle, casted);

без Thread.Sleep, без ThreadPool. Надеюсь, достаточно чисто Мог бы действительно использовать некоторых представителей, чтобы я мог комментировать решения других людей.

UPDATE:

Так как людям нравится симпатичный код:

public static class WpfExtensions
{
    public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
    {
        element.Dispatcher.BeginInvoke(priority, action);
    }
}

теперь вы можете назвать это так:

child.BeginInvoke(d => d.Focus());
4 голосов
/ 07 июля 2010

Я нашел хорошую серию постов в блоге, посвященных WPF.

Все они хороши для чтения, но третья часть посвящена настройке фокуса на элемент пользовательского интерфейса в UserControl.

3 голосов
/ 16 сентября 2009
  1. Установите пользовательский элемент управления на Focusable = "True" (XAML)
  2. Обработайте событие GotFocus на вашем элементе управления и вызовите yourTextBox.Focus ()
  3. Обработайте событие Loaded в вашем окне и вызовите yourControl.Focus ()

У меня есть пример приложения, работающего с этим решением, когда я печатаю. Если это не работает для вас, должно быть что-то конкретное для вашего приложения или среды, которая вызывает проблему. В вашем первоначальном вопросе я думаю, что проблема связана с привязкой. Надеюсь, это поможет.

3 голосов
/ 23 марта 2009

WPF поддерживает два разных вида фокуса:

  1. Фокус клавиатуры
  2. Логический фокус

Свойство FocusedElement получает или устанавливает логический фокус в области фокусировки. Я подозреваю, что у TextBox есть логическая фокусировка, но содержащая область фокусировки не является активной областью фокусировки. Ergo, у него нет фокуса клавиатуры.

Итак, вопрос в том, есть ли у вас несколько областей фокусировки в вашем визуальном дереве?

1 голос
/ 24 января 2011

После того, как у меня был «кошмар WPF Initial Focus Nightmare» и на основе некоторых ответов в стеке, следующее оказалось для меня лучшим решением.

Сначала добавьте свой App.xaml OnStartup () следующим образом:

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

Затем добавьте событие WindowLoaded также в App.xaml:

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 в основном не выполняется из-за некоторых базовых условий гонки.

Я нашел следующее решение лучше всего, так как оно используется глобально для всего приложения.

Надеюсь, это поможет ...

Оран

1 голос
/ 01 апреля 2009

Я обратил внимание на проблему, связанную с размещением WPC UserControls в ElementHosts, которые содержатся в Form, которая устанавливается как дочерний элемент MDI через свойство MdiParent.

Я не уверен, что это та же проблема, с которой сталкиваются другие, но вы углубляетесь в детали, перейдя по ссылке ниже.

Проблема с настройкой фокуса в пользовательском элементе управления WPF, размещенном в ElementHost в дочерней MDI-форме WindowsForms

...