it-swarm.com.de

WPF-MVVM: Festlegen des UI-Steuerungsfokus von ViewModel

Was ist eine bewährte Methode, um den Steuerungsfokus in der MVVM-Architektur festzulegen. 

Wie ich es mir vorstelle, ist dies eine Eigenschaft im ViewModel, die bei Bedarf eine Fokusänderung auslöst. Und dann müssen die UI-Steuerelemente diese Eigenschaft binden/abhören, damit bei einer Änderung der entsprechende Fokus gesetzt wird. 

Ich betrachte es als ViewModel-Sache, weil ich den Fokus entsprechend einstellen möchte, nachdem eine bestimmte Aktion vom ViewModel ausgeführt wurde, z. B. das Laden bestimmter Daten. 

Was ist die beste Praxis? 

42
Sonic Soul

Verwenden Sie die IsFocused Attached-Eigenschaft wie in Antwort hier vorgeschlagen: Setzen Sie den Fokus auf das Textfeld in WPF aus dem Ansichtsmodell (C #) .

Dann können Sie einfach an eine Eigenschaft in Ihrem Ansichtsmodell binden.

27
Snarfblatt

Wenn Sie Caliburn.Micro verwenden, ist hier ein Dienst, den ich erstellt habe, um den Fokus auf ein beliebiges Steuerelement in der von Screen geerbten Ansicht zu setzen.

Hinweis: Dies funktioniert nur, wenn Sie Caliburn.Micro für Ihr MVVM-Framework verwenden.

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

Wie benutzt man das?

Von Ihrem ViewModel, das von Caliburn.Micro.Screen oder Caliburn.Micro.ViewAware geerbt wurde

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

Wie es funktioniert?

Diese Methode versucht, nach einem Element in der visuellen Struktur der Ansicht zu suchen, und der Fokus wird auf ein übereinstimmendes Steuerelement gesetzt. Wenn kein solches Steuerelement gefunden wird, werden die von Caliburn.Micro verwendeten BindingConventions verwendet.

Zum Beispiel

Es wird nach der Eigenschaft in der BindingExpression des Steuerelements gesucht. Bei TextBox wird geprüft, ob diese Eigenschaft an die Text-Eigenschaft gebunden ist, und dann wird der Fokus gesetzt.

14
Kishore Kumar

Das ViewModel wirft der View ein Ereignis mit der Meldung, dass die Aktion abgeschlossen wurde, und der View legt den Fokus fest.

1
Alex Shtof

Sie könnten eine Schnittstelle für die Ansicht einführen, damit das ViewModel der Ansicht den Fokus zuweisen kann. Die BookLibrary-Beispielanwendung des WPF Application Framework (WAF) zeigt, wie das gemacht wird. Bitte schauen Sie sich das BookListViewModel an.

0
jbe

Die Frage wurde mehrmals gestellt, die Antworten gelten leider nur für WPF. Für Silberlicht mit MVVM können Sie auch mit jeder Eigenschaft binden, um Details zu erhalten. Besuchen Sie dazu den folgenden Link

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

0
Khalid Rafique