MVVMアーキテクチャでコントロールフォーカスを設定するのに適した方法は何ですか。
私がそれを想像する方法は、必要なときにフォーカスの変更をトリガーするViewModelのプロパティを使用することです。そして、UIコントロールにそのプロパティをバインド/リッスンさせて、プロパティが変更された場合に適切なフォーカスが設定されるようにします。
特定のデータの読み込みなど、特定のアクションがViewModelによって実行された後に適切なフォーカスを設定したいので、私はそれをViewModelのものと見なします。
ベストプラクティスは何ですか?
ここの回答で提案されているIsFocused Attachedプロパティを使用します: ビューモデルからのWPFのテキストボックスにフォーカスを設定します(C#)
その後、単にビューモデルのプロパティにバインドできます。
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プロパティにバインドされているかどうかが確認され、フォーカスが設定されます。
ViewModelは、アクションが完了したことを通知するイベントをViewにスローし、Viewはフォーカスを設定します。
Viewのインターフェイスを導入して、ViewModelがフォーカスを設定するようにViewに指示できるようにすることができます。 WPF Application Framework(WAF)のBookLibraryサンプルアプリケーションは、その方法を示しています。 BookListViewModelをご覧ください。
質問は数回尋ねられましたが、残念なことに、答えはWPFにのみ適用されます。 MVVMを使用したシルバーライトの場合、詳細については任意のプロパティにバインドすることもできます。次のリンクをご覧ください。
http://codenicely.blogspot.com/2012/01/how-to-set-textbox-focus-in-silverlight.html