web-dev-qa-db-fra.com

Impossible de définir le focus sur un enfant de UserControl

J'ai un UserControl qui contient un TextBox. Lorsque la fenêtre principale est chargée, je souhaite définir le focus sur cette zone de texte. J'ai donc ajouté Focusable="True" GotFocus="UC_GotFocus" à la définition UserControls et FocusManager.FocusedElement="{Binding ElementName=login}" à ma définition principale. Dans la méthode UC_GotFocus, j'appelle simplement .Focus() sur le contrôle sur lequel je veux me concentrer, mais cela ne fonctionne pas.

Tout ce que je dois faire est d'avoir une TextBox dans une UserControl recevoir le focus lorsque l'application démarre.

Toute aide serait appréciée Merci.

37
Stimul8d

J'ai récemment résolu ce problème pour un écran de démarrage de connexion qui est affiché via un storyboard lors du premier chargement de la fenêtre principale. 

Je crois qu'il y avait deux clés à la solution. L'une consistait à faire de l'élément contenant une portée de focus. L'autre consistait à gérer l'événement Storyboard Completed du storyboard déclenché par le chargement de la fenêtre. 

Ce storyboard rend visible le canevas de nom d'utilisateur et de mot de passe, puis devient opaque à 100%. La clé est que le contrôle de nom d'utilisateur n'était pas visible jusqu'à ce que le storyboard soit exécuté et que ce contrôle ne pouvait donc pas obtenir le focus keyboard tant qu'il n'était pas visible. Ce qui m'a déstabilisé pendant un moment, c’est qu’il avait un "focus" (c’est-à-dire que c’était vrai, mais il s’est avéré que c’était juste un focus logique) et je ne savais pas que WPF avait le concept de focus à la fois logique et clavier jusqu’à lire celui de Kent Boogaart. répondre et regarder le WPF de Microsoft texte du lien

Une fois que j'ai fait cela, la solution à mon problème particulier était simple:

1) Faire de l’élément contenant une portée de focus

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

2) attacher un gestionnaire d'événements terminé au storyboard

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

et

3) Définissez mon nom d’utilisateur TextBox pour que le clavier soit activé dans le gestionnaire d’événements terminé du storyboard.

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

Notez que l'appel de item.Focus () entraîne l'appel de Keyboard.Focus (this), vous n'avez donc pas besoin de l'appeler explicitement. Voir cette question à propos de la différence entre Keyboard.Focus (item) et item.Focus.

25
eesh

C'est stupide mais ça marche:

Pop un fil qui attend un moment puis revient et définit le focus que vous voulez. Cela fonctionne même dans le contexte d'un élément hôte.

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

                            }));
                        }
                   );

}
15
fuzquat

Récemment, j'avais une liste déroulante contenant des TextBlocks. Je voulais pouvoir double-cliquer sur le bloc de texte et le transformer en une zone de texte, puis me concentrer sur celui-ci et sélectionner tout le texte afin que l'utilisateur puisse simplement commencer à taper le nouveau nom (semblable aux calques Adobe)

Quoi qu'il en soit, je faisais cela avec un événement et cela ne fonctionnait tout simplement pas. La solution miracle pour moi ici était de veiller à ce que l'événement soit géré. Je pensais que était mettait le focus, mais dès que l'événement se produisait, il basculait le focus logique.

La morale de l’histoire est la suivante: assurez-vous de marquer l’événement comme étant géré, cela pourrait être votre problème.

7
Vassi

«Lors de la définition de la focalisation initiale au démarrage de l'application, l'élément à recevoir doit être connecté à un PresentationSource et doit avoir pour valeur Focusable et IsVisible. L'emplacement recommandé pour définir le focus initial est dans le gestionnaire d'événements chargé "(MSDN)

Ajoutez simplement un gestionnaire d'événements "Loaded" dans le constructeur de votre fenêtre (ou de votre contrôle) et, dans ce gestionnaire d'événements, appelez la méthode Focus () sur le contrôle cible.

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

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

depuis que j'ai essayé une solution de fuzquat et que je l'ai trouvée la plus générique, j'ai pensé partager une version différente, car certains se sont plaints de son apparence désordonnée. alors le voici:

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

pas de Thread.Sleep, pas de ThreadPool. Assez propre j'espère. Pourrait vraiment utiliser un représentant afin que je puisse commenter les solutions des autres peuples.

METTRE À JOUR:

Puisque les gens semblent aimer le joli code:

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

maintenant vous pouvez l'appeler comme ceci:

child.BeginInvoke(d => d.Focus());
5
Dbl

J'ai trouvé une bonne série de billets de blog sur WPF Focus.

Ils sont tous bons à lire, mais la 3ème partie traite spécifiquement de la définition du focus sur un élément d'interface utilisateur dans un UserControl.

4
Ashley Davis

WPF prend en charge deux types de focus différents:

  1. Focus clavier
  2. Focus logique

La propriété FocusedElement obtient ou définit le focus logique dans une portée de focus. Je soupçonne que votre TextBox a a le focus logique, mais sa portée cible ne correspond pas à celle active Ergo, il n'a pas a le focus clavier.

La question est donc de savoir si vous avez plusieurs portées de focalisation dans votre arbre visuel.

3
Kent Boogaart
  1. Définissez votre contrôle utilisateur sur Focusable = "True" (XAML)
  2. Gérez l’événement GotFocus sur votre contrôle et appelez yourTextBox.Focus ()
  3. Gérez l'événement Loaded sur votre fenêtre et appelez yourControl.Focus ()

J'ai un exemple d'application en cours d'exécution avec cette solution au fur et à mesure que je tape. Si cela ne fonctionne pas pour vous, il doit exister un problème spécifique à votre application ou à votre environnement. Dans votre question initiale, je pense que la liaison est à l'origine du problème ... J'espère que cela vous aidera.

3
Josh F.

J'ai converti la réponse de fuzquat en une méthode d'extension. J'utilise ceci au lieu de Focus () où Focus () n'a pas fonctionné.

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();
                }));
            });
        }
    }
}
1
Tempeck

J'ai remarqué un problème de focus spécifiquement lié à l'hébergement de WPF UserControls dans ElementHosts, contenus dans un formulaire défini en tant qu'enfant MDI via la propriété MdiParent.

Je ne suis pas sûr qu'il s'agisse du même problème que d'autres, mais vous pouvez creuser dans les détails en suivant le lien ci-dessous.

Problème lié à la définition de la focalisation dans un utilisateur WPF UserControl hébergé dans un ElementHost dans un formulaire MDI enfant WindowsForms

1
jpierson

Qu'est-ce que le truc pour moi a été l'attribut FocusManager.FocusedElement . J'ai d'abord essayé de le définir sur UserControl, mais cela n'a pas fonctionné.

J'ai donc essayé de le placer sur le premier enfant de 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>

... et ça a fonctionné! :)

1
Crono

Après avoir eu un 'WPF Initial Focus Nightmare' et basé sur quelques réponses sur pile, ce qui suit s’est révélé être pour moi la meilleure solution. 

Tout d’abord, ajoutez votre App.xaml OnStartup () aux éléments suivants:

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

Ajoutez ensuite l'événement 'WindowLoaded' également dans 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));

        }));
    }

Le problème de thread doit être utilisé car la focalisation initiale de WPF échoue principalement en raison de certaines conditions de concurrence du framework.

J'ai trouvé la solution suivante la meilleure car elle est utilisée globalement pour l'ensemble de l'application.

J'espère que ça aide...

Oran

1
OrPaz

Je le mets dans le PageLoaded () ou le contrôle chargé, mais ensuite j'appelle le service WCF asynchrone et fais des choses qui semblent perdre le focus. Je dois le mettre à la fin de tout ce que je fais. C'est bien et tout, mais parfois, j'apporte des modifications au code, puis j'oublie que je mets également le curseur.

0
Dan Parker

Je n'aime pas les solutions consistant à définir un autre champ de tabulation pour UserControl. Dans ce cas, vous utiliserez deux caractères différents lorsque vous naviguez au clavier: sur la fenêtre et l'autre - dans le contrôle de l'utilisateur. Ma solution consiste simplement à rediriger le focus du contrôle de l'utilisateur vers le contrôle interne de l'enfant. Définissez le contrôle de l'utilisateur sur focusable (car par défaut, il est faux):

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

et remplacer les gestionnaires d'événements focus dans code-behind:

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

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

En supposant que vous souhaitiez définir le focus pour la zone de texte Nom d'utilisateur, l'utilisateur peut saisir directement chaque fois qu'il s'affiche.

En constructeur de votre commande:

this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
0
Thai Anh Duc

J'ai contrôle utilisateur - panneau de pile avec deux zones de texte. Les zones de texte ont été ajoutées dans le constructeur, pas dans le xaml. Lorsque j'essaie de me concentrer sur la première zone de texte, il ne se passe rien .. La siggestion avec événement chargé corrige mon problème Vient d’appeler control.Focus () dans Evénement chargé et tout. 

0
charino

Après avoir essayé différentes combinaisons des suggestions ci-dessus, j'ai pu affecter de manière fiable le focus à une zone de texte souhaitée sur un UserControl enfant avec les éléments suivants. Fondamentalement, mettez l'accent sur le contrôle enfant et demandez à l'enfant UserControl de mettre l'accent sur sa zone de texte. La déclaration de focus de la zone de texte a renvoyé la valeur true par elle-même, mais n'a pas donné le résultat souhaité jusqu'à ce que le contrôle UserControl ait également été activé. Je devrais également noter que le UserControl était incapable de demander le focus pour lui-même et devait être donné par la fenêtre.

Par souci de brièveté, j'ai omis d'enregistrer les événements chargés sur la fenêtre et sur UserControl.

La fenêtre

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

UserControl

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