2009-07-24 12 views
45

Mam widok, który ma jeden TextBox i kilka Button s poniżej. Po załadowaniu okna chcę ustawić ostrość na TextBox.WPF Pole widzenia MVVM na obciążenie

Jeśli nie korzystałem z MVVM, zadzwoniłbym pod numer TextBox.Focus() w zdarzeniu Załadowano. Jednak mój ViewModel nie wie o moim widoku, więc jak mogę to zrobić bez umieszczania kodu w kodzie behind mojego widoku?

EDIT: Po przeczytaniu odpowiedzi postanowiłem umieścić ten kod w widoku XAML

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

Gdyby to było coś innego niż strona początkowa Focus I prawdopodobnie polecić odpowiedź Jon Galloway jest, ponieważ może być sterowany ViewModel.

Odpowiedz

44

Jeśli to sprawia, że ​​czujesz się lepiej (to sprawia, że ​​lepiej czuje) można to zrobić w XAML za pomocą dołączonego właściwość:

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

Wszystko można zrobić w kodzie można zrobić w XAML jeśli ciebie znać sztuczki. Na szczęście nie trzeba było wprowadzać tej sztuczki - MS zrobiło to za Ciebie.

+0

Tego właśnie szukałem. Myślę, że ten kod należy do widoku iz jakiegoś powodu podoba mi się go lepiej w xaml niż w kodzie. –

+2

Sugestia Galloway pozwala kontrolować ostrość z ViewModel ... możesz również przyjrzeć się temu bliżej. –

+3

Po przeczytaniu niektórych innych odpowiedzi nie jestem pewien, czy kod należy do ViewModel. Wydaje się być związany bezpośrednio z widokiem. Gdybym miał bardziej złożoną stronę, która faktycznie poruszałaby fokus na podstawie innych zdarzeń, które prawdopodobnie miałyby sens. To powiedziało, że nadal jest to fajna sztuczka. –

14

W tym przypadku myślę, że dobrze jest umieścić kod w widoku. Ustawienie ostrości na kontrolkę wpływa na zachowanie interfejsu użytkownika, a nie na logikę aplikacji, a zatem jest odpowiedzialnością za widok.

+1

Że niby co myślałem. Czuję się trochę brudny za każdym razem, gdy myślę o dodaniu kodu do widoku. W tym przypadku wydaje się to mieć jednak sens. –

+14

Myślę, że kiedy zmieniłem moją filozofię MVVM z "bez kodu" na "minimalny i istotny kod z tyłu" moje życie stało się o wiele łatwiejsze. Nie słyszałem o załączonej nieruchomości, o której wspomniał Anderson Imes, i brzmi to jak dobre rozwiązanie dla złego smaku, jaki daje kod, ale nie bój się umieścić * legalnego *, nielogicznego kodu w Interfejs użytkownika. –

+4

Zgadzam się z tobą. Nie sądzę, że ma sens religijne podejście do eliminowania kodu z widoku. Ważną rzeczą jest to, że kod w widoku powinien być bardzo podobny do interfejsu użytkownika. Kod w maszynie wirtualnej zawiera stan i inną logikę odnoszącą się do modelu. Papierkiem lakmusowym jest sprawdzenie, czy kod może/powinien być testowany. Kod w widoku NIE może być testowany. –

4

Uważam, że kontrola z naciskiem jest bardzo "wizualna", więc nie miałaby problemu z tym, że jest w kodzie.

Ideą maszyny wirtualnej jest przeniesienie logiki z widoku i udostępnienie modelowi przyjaznej dla wiązania danych modelu, z którym ma zostać powiązany widok. Nie musi to oznaczać, że kod musi być w VM, tylko kod logiczny i wszystko, co nie jest bezpośrednio związane z interfejsem użytkownika.

8

Właściwie, czy koncentracja nie dotyczy interfejsu użytkownika? MVVM polega na rozdzielaniu obaw - to, co należy do modelu, to w modelu, co należy do widoku, i jaki model powiązania i widoku razem jest w ViewModel (jest to oczywiście uproszczony opis).

Oznacza to, że logika interfejsu użytkownika pozostaje w widoku - TextBox.Focus() jest, moim zdaniem, odpowiednim sposobem, aby to się stało.

10
  1. Masz właściwość w swoim ViewModelu, która wskazuje, który element jest aktualnie skupiony.
  2. Użyj Menedżera ostrości, aby powiązać tę właściwość.

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

Twój ViewModel jest tłumacz, który istnieje wyłącznie w celu dostarczenia informacji na temat widoku, dzięki czemu można dodawać wszelkie informacje na VM, że widok musi funkcjonować.

+4

Ale musisz wymienić wszystkie swoje elementy i użyć tej nazwy w VM. Nie zadziała to, jeśli masz kolekcję elementów w maszynie wirtualnej, do której widok jest wiążący. – Carlos

+7

IMHO, maszyna wirtualna nie powinna mieć żadnych informacji o nazwach kontrolek lub typach w rzeczywistej implementacji widoku. Zamiast tego pozwoliłem, aby widok nasłuchiwał powiadomienia o zmianie właściwości z maszyny wirtualnej, a następnie niech to obsłuży. na przykład ActivateNameField przechodzi do wartości true. Widok znajduje odpowiednią kontrolę i ustawia na niej fokus. – Gishu

+1

Zgadzam się, że maszyna wirtualna musi odgrywać rolę w procesie, gdy zaangażowana jest logika biznesowa. Gdy projekt zażąda "kiedy zaznaczą to pole wyboru, a oni są administratorem, ustawiają fokus na pole tekstowe OverrideReason", wtedy logika należy do VM. Sztuczka polega na tym, że View przestrzega zmiany własności. – TheZenker

2

Po "Koszcie początkowym WPF" i na podstawie kilku odpowiedzi na stosie, najlepsze rozwiązanie okazało się dla mnie następujące.

Najpierw dodaj swoją aplikację.XAML OnStartup() następujących:

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

Następnie dodać zdarzenie „WindowLoaded” również w App.xaml:

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

     })); 
    } 

Kwestia gwintowania musi być użyty jako WPF początkowym naciskiem głównie nie ze względu na pewne ramy Warunki wyścigu.

Znalazłem następujące rozwiązanie najlepiej, ponieważ jest używane globalnie dla całej aplikacji.

nadzieję, że to pomaga ...

Oran

Powiązane problemy