Подтвердить что ты не робот

Не удается установить фокус на дочерний элемент UserControl

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

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

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

4b9b3361

Ответ 1

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

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

Эта раскадровка делает видимость имени пользователя и пароля видимой, а затем исчезает на 100% непрозрачной. Ключ состоит в том, что элемент управления именем пользователя не был виден до тех пор, пока не будет запущена раскадровка, и поэтому этот элемент управления не сможет получить фокус клавиатуры, пока он не станет видимым. То, что отбросило меня на некоторое время, было то, что у него был "фокус" (т.е. Фокус был правдой, но, как выясняется, это был только логический фокус), и я не знал, что WPF имеет концепцию как логической, так и клавиатуры, до тех пор, пока не прочитает Kent Boogaart ответьте и посмотрите на Microsoft WPF текст ссылки

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

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(это), поэтому вам не нужно явно вызывать это. См. Этот вопрос о разнице между Keyboard.Focus(item) и item.Focus.

Ответ 2

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

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

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

                            }));
                        }
                   );

}

Ответ 3

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

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

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

Ответ 4

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

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

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

    void MyWindow_Loaded(object sender, RoutedEventArgs e) {
        textBox.Focus();
    }

Ответ 5

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

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

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

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

Ответ 6

Я нашел хорошую серию сообщений в блоге в фокусе WPF.

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

Ответ 7

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

  • Фокус клавиатуры
  • Логическая фокусировка

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

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

Ответ 8

  • Задайте свой пользовательский элемент управления Focusable = "True" (XAML)
  • Обработайте событие GotFocus на своем элементе управления и вызовите yourTextBox.Focus()
  • Обработайте событие Загруженное в своем окне и вызовите yourControl.Focus()

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

Ответ 9

Я заметил проблему с фокусом, специально связанную с размещением WPF UserControls внутри ElementHosts, которые содержатся в Форме, которая устанавливается как дочерний MDI через свойство MdiParent.

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

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

Ответ 10

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

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

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

Оран

Ответ 11

Какая уловка для меня была атрибутом FocusManager.FocusedElement. Сначала я попытался установить его в UserControl, но это не сработало.

Итак, я попытался поместить его в первый дочерний элемент UserControl:

<UserControl x:Class="WpfApplication3.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
    <TextBox x:Name="MyTextBox"/>
</Grid>

... и это сработало!:)

Ответ 12

Я преобразовал ответ fuzquat в метод расширения. Я использую это вместо Focus(), где Focus() не работает.

using System;
using System.Threading;
using System.Windows;

namespace YourProject.Extensions
{
    public static class UIElementExtension
    {
        public static void WaitAndFocus(this UIElement element, int ms = 100)
        {
            ThreadPool.QueueUserWorkItem(f =>
            {
                Thread.Sleep(ms);

                element.Dispatcher.Invoke(new Action(() =>
                {
                    element.Focus();
                }));
            });
        }
    }
}

Ответ 13

У меня есть пользовательский элемент управления - панель стека с двумя текстовыми полями. Текстовые поля были добавлены в contructor, а не в xaml. Когда я пытаюсь сфокусировать первое текстовое поле, ничего не происходит. Исправлена ​​проблема с загруженным событием. Просто вызывается control.Focus() в Loaded event и everthing.

Ответ 14

Предполагая, что вы хотите установить фокус для текстового поля Username, таким образом, пользователь может вводить данные непосредственно при каждом появлении.

В конструкторе вашего управления:

this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);

Ответ 15

После того, как вы попытались сочетать приведенные выше предложения, я смог надежно назначить фокус на нужное текстовое поле для дочернего UserControl со следующим. В основном, сосредоточьтесь на контроле над детьми и попросите его UserControl сосредоточиться на своем TextBox. Оператор фокуса TextBox верен сам по себе, однако не дал желаемого результата, пока UserControl также не уделял внимания. Следует также отметить, что UserControl не смог запросить фокус для себя и должен был быть предоставлен Окном.

Для краткости я не регистрировал события Loaded в окне и UserControl.

Окно

private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
    ControlXYZ.Focus();
}

UserControl

private void OnControlLoaded(object sender, RoutedEventArgs e)
{
    TextBoxXYZ.Focus();
}

Ответ 16

Я установил его в файле PageLoaded() или control, но потом я звоню в службу WCF async и делаю вещи, которые, похоже, теряют фокус. Я должен установить его в конце всего, что я делаю. Это прекрасно и все, но иногда я вношу изменения в код, а затем забываю, что я также устанавливаю курсор.

Ответ 17

Мне не нравятся решения с установкой другой области вкладок для UserControl. В этом случае при навигации по клавиатуре у вас будет два разных режима: в окне и в другом - внутри пользователя. Мое решение - просто перенаправить фокус с пользовательского контроля на внутренний дочерний элемент управления. Задайте управляемый элемент управления (поскольку по умолчанию его значение false):

<UserControl ..... Focusable="True">

и переопределить обработчики фоновых событий в коде:

protected override void OnGotFocus(RoutedEventArgs e)
{
    base.OnGotFocus(e);
    MyTextBox.Focus();
}

protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
    base.OnGotKeyboardFocus(e);
    Keyboard.Focus(MyTextBox);
}

Ответ 18

У меня была такая же проблема с установкой фокуса клавиатуры на холст в пользовательском элементе управления WPF. Мое решение

  • В элементе набора XAML для Focusable="True"
  • В событии element_mousemove создайте простую проверку:

    if(!element.IsKeyBoardFocused)
        element.Focus();
    

В моем случае это нормально работает.