web-dev-qa-db-fra.com

Champ de concentration WPF MVVM sur la charge

J'ai une vue qui a un seul TextBox et quelques Button en dessous. Lorsque la fenêtre se charge, je veux que TextBox ait le focus.

Si je n'utilisais pas MVVM, j'appellerais simplement TextBox.Focus() dans l'événement Loaded. Cependant, mon ViewModel ne connaît pas ma vue, alors comment puis-je accomplir cela sans mettre de code dans le code derrière ma vue?

EDIT: Après avoir lu les réponses, j'ai décidé de mettre ce code dans la vue xaml

<DockPanel FocusManager.FocusedElement="{Binding ElementName=MessageTextBox}">    
    <TextBox Name="MessageTextBox" Text="{Binding Message}"/>
</DockPanel>

Si c'était autre chose que le focus de la page initiale, je recommanderais probablement la réponse de Jon Galloway car elle peut être contrôlée à partir du ViewModel.

48
Shaun Bowe

Si cela vous fait vous sentir mieux (ça me fait me sentir mieux), vous pouvez le faire dans Xaml en utilisant une propriété attachée:

http://msdn.Microsoft.com/en-us/library/system.windows.input.focusmanager.focusedelement.aspx

Tout ce que vous pouvez faire en code derrière vous pouvez le faire en Xaml si vous connaissez les astuces. Heureusement, vous n'avez pas eu à mettre en œuvre cette astuce - MS l'a fait pour vous.

50
Anderson Imes

Dans ce cas, je pense que c'est bien de mettre le code dans la vue. La définition du focus sur un contrôle affecte le comportement de l'interface utilisateur plutôt que la logique de l'application et relève donc de la responsabilité de la vue.

14
Martin Harris
  1. Avoir une propriété dans votre ViewModel qui indique quel est l'élément actuellement focalisé.
  2. Utilisez le FocusManager pour vous lier à cette propriété.

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

Votre ViewModel est un traducteur qui existe uniquement pour fournir des informations à la vue, vous pouvez donc ajouter toutes les informations à la VM dont la vue a besoin pour fonctionner.

9
Jon Galloway

En fait, le focus n'est-il pas une préoccupation d'interface utilisateur? MVVM consiste à séparer les préoccupations - ce qui appartient au modèle est dans le modèle, ce qui appartient à la vue est en vue, et ce qui lie le modèle et la vue ensemble est dans ViewModel (c'est bien sûr une description simplifiée).

Cela signifie que la logique de l'interface utilisateur reste dans View - TextBox.Focus () est, à mon avis, le moyen approprié pour y arriver.

8
maciejkow

Je considérerais le contrôle avec le focus comme étant "visuel uniquement", donc je n'aurais aucun problème avec le fait qu'il soit en code derrière.

L'idée d'un VM est d'éloigner la logique de la vue et de fournir une version conviviale de liaison de données de votre modèle pour la vue à laquelle se lier. Cela ne signifie pas nécessairement que all le code devrait vivre dans la machine virtuelle, juste le code logique et tout ce qui n'est pas directement lié à l'interface utilisateur.

4
Steven Robbins

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

Tout d'abord, ajoutez votre App.xaml OnStartup () comme suit:

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 le focus initial WPF échoue principalement en raison de certaines conditions de concurrence du framework.

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

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

Oran

2
OrPaz