web-dev-qa-db-ja.com

WPF-MVVM:ViewModelからのUIコントロールフォーカスの設定

MVVMアーキテクチャでコントロールフォーカスを設定するのに適した方法は何ですか。

私がそれを想像する方法は、必要なときにフォーカスの変更をトリガーするViewModelのプロパティを使用することです。そして、UIコントロールにそのプロパティをバインド/リッスンさせて、プロパティが変更された場合に適切なフォーカスが設定されるようにします。

特定のデータの読み込みなど、特定のアクションがViewModelによって実行された後に適切なフォーカスを設定したいので、私はそれをViewModelのものと見なします。

ベストプラクティスは何ですか?

45
Sonic Soul

ここの回答で提案されているIsFocused Attachedプロパティを使用します: ビューモデルからのWPFのテキストボックスにフォーカスを設定します(C#)

その後、単にビューモデルのプロパティにバインドできます。

29
Snarfblatt

Caliburn.Microを使用している場合、画面から継承されたビュー内の任意のコントロールにフォーカスを設定するために作成したサービスを次に示します。

注:これは、MVVMフレームワークにCaliburn.Microを使用している場合にのみ機能します。

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

これの使い方は?

Caliburn.Micro.ScreenまたはCaliburn.Micro.ViewAwareから継承したViewModelから

this.SetFocus(()=>ViewModelProperty);またはthis.SetFocus("Property");

使い方?

このメソッドは、ビューのビジュアルツリー内の要素を検索しようとし、一致するコントロールにフォーカスが設定されます。そのようなコントロールが見つからない場合、Caliburn.Microが使用するBindingConventionsを使用します。

たとえば、

コントロールのBindingExpressionでプロパティを探します。 TextBoxの場合、このプロパティがTextプロパティにバインドされているかどうかが確認され、フォーカスが設定されます。

14
Kishore Kumar

ViewModelは、アクションが完了したことを通知するイベントをViewにスローし、Viewはフォーカスを設定します。

1
Alex Shtof

Viewのインターフェイスを導入して、ViewModelがフォーカスを設定するようにViewに指示できるようにすることができます。 WPF Application Framework(WAF)のBookLibraryサンプルアプリケーションは、その方法を示しています。 BookListViewModelをご覧ください。

0
jbe

質問は数回尋ねられましたが、残念なことに、答えはWPFにのみ適用されます。 MVVMを使用したシルバーライトの場合、詳細については任意のプロパティにバインドすることもできます。次のリンクをご覧ください。

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

0
Khalid Rafique