50 votes

WPF-MVVM: Définition du focus de contrôle d'interface utilisateur à partir de ViewModel

Ce qui est une bonne pratique de l'établissement de contrôle de la focalisation dans l'architecture MVVM.

La façon dont je l'imagine, est une propriété du ViewModel qui pourrait déclencher un changement de focus en cas de besoin. Et que les contrôles de l'INTERFACE utilisateur bind/écouter de la propriété, de sorte que si elle change, approprié, l'accent sera mis.

Je le vois comme un ViewModel chose, parce que je tiens à mettre l'accent approprié après une action a été réalisée par le ViewModel, telles que le chargement de certaines données.

Quelle est la meilleure pratique?

33voto

Snarfblatt Points 332

Utilisez la propriété attachée IsFocused comme suggéré dans la réponse ici: Définissez le focus sur la zone de texte dans WPF à partir du modèle d'affichage (C #) & wPF.

Ensuite, vous pouvez simplement vous lier à une propriété dans votre viewmodel.

15voto

Si vous êtes à l'aide de Caliburn.Micro, ici, c'est un service que j'ai créé pour définir le Focus à tout Contrôle dans la vue hérité de l'Écran.

Remarque: Cela ne fonctionne que si vous utilisez Caliburn.Micro pour votre MVVM cadre.

public static class FocusManager
{
    public static bool SetFocus(this IViewAware screen ,Expression<Func<object>> propertyExpression)
    {
        return SetFocus(screen ,propertyExpression.GetMemberInfo().Name);
    }

    public static bool SetFocus(this IViewAware screen ,string property)
    {
        Contract.Requires(property != null ,"Property cannot be null.");
        var view = screen.GetView() as UserControl;
        if ( view != null )
        {
            var control = FindChild(view ,property);
            bool focus = control != null && control.Focus();
            return focus;
        }
        return false;
    }

    private static FrameworkElement FindChild(UIElement parent ,string childName)
    {
        // Confirm parent and childName are valid. 
        if ( parent == null || string.IsNullOrWhiteSpace(childName) ) return null;

        FrameworkElement foundChild = null;

        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);

        for ( int i = 0; i < childrenCount; i++ )
        {
            FrameworkElement child = VisualTreeHelper.GetChild(parent ,i) as FrameworkElement;
            if ( child != null )
            {

                BindingExpression bindingExpression = GetBindingExpression(child);
                if ( child.Name == childName )
                {
                    foundChild = child;
                    break;
                }
                if ( bindingExpression != null )
                {
                    if ( bindingExpression.ResolvedSourcePropertyName == childName )
                    {
                        foundChild = child;
                        break;
                    }
                }
                foundChild = FindChild(child ,childName);
                if ( foundChild != null )
                {
                    if ( foundChild.Name == childName )
                        break;
                    BindingExpression foundChildBindingExpression = GetBindingExpression(foundChild);
                    if ( foundChildBindingExpression != null &&
                        foundChildBindingExpression.ResolvedSourcePropertyName == childName )
                        break;
                }

            }
        }

        return foundChild;
    }

    private static BindingExpression GetBindingExpression(FrameworkElement control)
    {
        if ( control == null ) return null;

        BindingExpression bindingExpression = null;
        var convention = ConventionManager.GetElementConvention(control.GetType());
        if ( convention != null )
        {
            var bindablePro = convention.GetBindableProperty(control);
            if ( bindablePro != null )
            {
                bindingExpression = control.GetBindingExpression(bindablePro);
            }
        }
        return bindingExpression;
    }
}

Comment l'utiliser?

À partir de votre ViewModel hérité de Caliburn.Micro.De l'écran ou de Caliburn.Micro.ViewAware

this.SetFocus(()=>ViewModelProperty); ou this.SetFocus("Property");

Comment cela fonctionne?

Cette méthode va essayer de rechercher un élément dans l'Arborescence Visuelle de Vue et l'accent sera mis tout contrôle de la concordance. Si un tel contrôle, il fera usage de la BindingConventions utilisé par Caliburn.Micro.

Ex.:

Il va chercher la Propery dans le BindingExpression du contrôle. Pour la zone de texte, il va chercher à savoir si cette propriété est lié à la propriété de Texte puis l'accent sera mis.

1voto

Alex Points 521

ViewModel envoie un événement à la vue en lui indiquant que l'action est terminée et la vue définit le focus.

0voto

jbe Points 4629

Vous pouvez introduire une interface pour la vue afin que ViewModel puisse indiquer à la vue de définir le focus. L'exemple d'application BookLibrary du WPF Application Framework (WAF) montre comment procéder. S'il vous plaît jeter un oeil à la BookListViewModel.

0voto

Khalid Rafique Points 53

La question a été posée à plusieurs reprises. Malheureusement, les réponses ne concernent que WPF. Donc, pour une lumière argentée utilisant MVVM, vous pouvez également associer n'importe quelle propriété pour plus de détails, veuillez visiter le lien suivant

http://codenicely.blogspot.com/2012/01/how-to-set-textbox-focus-in-silverlight.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X