2009-07-24 30 views
45

私はビューが1つしかありません。TextBoxとその下にあるのはButtonです。ウィンドウがロードされたら、TextBoxにフォーカスが欲しいです。WPF MVVM Focus Field on Load

MVVMを使用していない場合は、LoadedイベントでTextBox.Focus()と呼ぶだけです。しかし、私のViewModelは私のビューについて知らないので、私のビューのコードビハインドにコードを入れないでこれをどのように達成できますか?

EDIT: は答えを読んだ後、私は、ビューのXAMLで

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

をこのコードを配置することを決め、これが最初のページのフォーカス以外のものであれば、それはから制御することができるので、私はおそらく、ジョン・ギャロウェイの答えをお勧めしますViewModel

答えて

44

それは(それは私がより良い感じさせる)あなたが良い感じになります場合は、添付プロパティを使用してXAMLでこれを行うことができます:

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

あなた場合は、XAMLで行うことができます分離コードで何かできることトリックを知っている。幸いにも、あなたはこのトリックを実装する必要はありませんでした - MSはあなたのためにそれを行いました。

+0

これはまさに私が探していたものです。私はこのコードがビューに属していると思うし、何らかの理由で私はそれがコードの背後にあるxamlの方がより好きです。 –

+2

Gallowayの提案は、ViewModelからフォーカスを制御することを可能にします...あなたも同様にそれを詳しく見ることができます。 –

+3

他の回答の一部を読んだあと、そのコードがViewModelに属しているかどうかわかりません。それは見方に直接結びついているようです。おそらく理にかなっている他のイベントに基づいて実際にフォーカスを移動していたより複雑なページがあれば、それはまだそれが素晴らしいトリックだと言いました。 –

14

この場合、コードをビューに入れることは問題ないと思います。コントロールにフォーカスを設定すると、アプリケーションのロジックではなくユーザーインターフェイスの動作に影響します。そのため、ビューの責任があります。

+1

。私は、ビューにコードを追加すると思うたびにちょっと汚いと感じます。この場合、それは理にかなっているようです。 –

+14

MVVMの考え方を「コードなし」から「最小限かつ適切なコードの背後」に変更すると、私の人生はずっと楽になりました。アンダーソン・イメスが言及している添付のプロパティについては聞いていませんでしたが、悪い味の良い解決策のように聞こえますが、コードビハインドがあなたに与えるものですが、正当な*非論理コードをUI。 –

+4

私はあなたに同意しています。私は、見解からコードを削除することについて宗教的になるのは理にかなっているとは思わない。重要なことは、ビュー内のコードが非常にUIに関連していることです。 VM内のコードには、モデルに関連する状態やその他のロジックが含まれています。リトマステストとは、コードをテストできるかどうかをテストすることです。ビュー内のコードはテストできません。 –

4

私は、フォーカスを持ったコントロールが非常に「視覚的な」ものであると考えているので、コードの背後にあることに何の問題もありません。

VMの考え方は、ロジックをビューから移動して、ビューをバインドするためのモデルのデータバインディングに適したバージョンを提供することです。これは必ずしもすべてコードがVM内に存在することを意味するものではなく、ロジックコードとUIに直接結び付けられていないものだけを意味します。

8

実際には、UIに焦点を当てていませんか? MVVMは、モデルに属しているものがモデルに属し、ビューに属するものがビューにあり、バインドモデルとビューがViewModelに含まれているもの(これはもちろん単純すぎる記述です)をMVVMは分離します。

これは、UIロジックがView - TextBox.Focus()に残っていることを意味します。これは、私の意見では、これを実現する適切な方法です。

10
  1. ViewModelには、現在フォーカスされている要素がどれかを示すプロパティがあります。
  2. FocusManagerを使用して、そのプロパティにバインドします。

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

あなたのViewModelを使用すると、ビューが機能するために必要なことをVMにどんな情報を追加できるように、単に、ビューに情報を提供するために存在する翻訳者です。

+4

しかし、すべての要素に名前を付けて、その名前をVMで使用する必要があります。ビューがバインドされているVM内にアイテムのコレクションがある場合、これは機能しません。 – Carlos

+7

IMHOでは、実際のビューの実装では、VMはコントロール名や型に関する情報を持たないはずです。代わりに、私はビューがVMからプロパティの変更の通知をリッスンして、それを処理させるようにします。例えばActivateNameFieldがtrueになります。Viewは関連するコントロールを見つけて、フォーカスをフォーカスに設定します。 – Gishu

+1

私は、ビジネスロジックが関与しているときにVMがそのプロセスで役割を持たなければならないことに同意します。デザインが「このチェックボックスを選択し、管理者である場合は、OverrideReasonテキストボックスにフォーカスを設定する」と要求されると、ロジックはVMに属します。そのトリックは、プロパティの変更を尊重するようにビューを取得しています。 – TheZenker

2

「WPF初期フォーカスナイトメア」を持って、スタック上のいくつかの回答に基づいて、以下が私にとって最善の解決策であることが証明されました。

まず、あなたのアプリケーションを追加してください。XAML OnStartup()以下:

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent, 
      new RoutedEventHandler(WindowLoaded)); 

はその後App.xamlでも「WindowLoaded」イベントを追加します。

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

     })); 
    } 

WPF最初の焦点は、ほとんどが何らかの枠組みに失敗したとして、スレッド問題が使用でなければなりません競争条件。

アプリ全体でグローバルに使用されているため、以下の解決策が最もよく見つかりました。私が考えたものの一種である、それは助け

希望...

オラン