2009-08-26 15 views
36

Właśnie dostaję się do MVVM w WPF.Czy MVVM ViewModel wykonuje konwersję/sprawdzanie typu?

Wdrożyliśmy nasze ViewModels z "mocno wpisanymi" właściwościami (int, double? Itd.), Które wiążemy w widoku.

Konwersja typów działa prawidłowo, w większości przypadków więc wprowadzanie danych jest dość proste. Ale mamy problemy z zatwierdzaniem.

Jeśli, powiedzmy, wartość nielicznikowa zostanie wprowadzona w polu tekstowym powiązanym z właściwością liczbową, konwersja nie powiedzie się, właściwość nigdy nie zostanie ustawiona i nigdy nie dostaniemy szansy na przekazanie użytkownikowi właściwej informacji zwrotnej. Co gorsza, właściwość zachowuje aktualną wartość, co prowadzi do niezgodności między tym, co jest wyświetlane w widoku, a tym, co faktycznie jest w ViewModelu.

Wszystko to może być obsługiwane za pomocą konwerterów wartości, wiem. Ale widziałem kilka opinii mówiących, że nawrócenie nie powinno być w ogóle odpowiedzialnością za pogląd. To, co jest wpisane w widoku, to łańcuchy znaków, a konwersja, walidacja itp. Powinny być odpowiedzialnością ViewModel (więc argument idzie).

Jeśli tak, powinniśmy przepisać większość właściwości w naszych modelach ViewModels na napisy i dostarczyć informacji o błędach za pomocą interfejsu IErrorInfo, na przykład. Z pewnością przyczyniłoby się to do uproszczenia i uproszczenia widoku XAML. Z drugiej strony konwersja, walidacja itp. Będą mniej deklaratywne, jednoznaczne i elastyczne, z punktu widzenia projektanta View.

Wydaje nam się, że te dwa podejścia są zasadniczo różne, więc zanim zdecydujemy, chcielibyśmy uzyskać pewne uzasadnione opinie SO w tej sprawie.

Tak: czy ViewModels powinien udostępniać w widoku uproszczony interfejs oparty na tekście i obsługiwać konwersję wewnętrznie? A może właściwości ViewModel powinny ujawniać rzeczywiste typy danych, pozostawiając takie zadania w widoku do obsługi?

Aktualizacja:

ciężko wybrać zwycięzcę tutaj, ale ostatecznie wylądował na jednym z was, która zawiera mniej lub bardziej jak ja.

W szczególności zdecydowaliśmy się zachować właściwości ViewModel wpisane. Główną tego przyczyną jest elastyczność, jaką daje nam w projektowaniu widoku oraz moc jawnej, deklaratywnej konwersji/formatowania w XAML.

Zauważyłem z tobą założenie, które nie zgadza się z nami w tej kwestii, że projekt widoku jest stały i gotowy. W związku z tym nie trzeba podejmować żadnych decyzji dotyczących konwersji, formatowania itp. Ale nasz jest zwinnym procesem, a nie mamy jeszcze wszystkich ważnych szczegółów interfejsu użytkownika.

W rzeczywistości pozostawienie szczegółów interfejsu użytkownika do opracowania po drodze pozostawia miejsce na kreatywność, a poza tym, moim zdaniem, nawet skrupulatnie opracowany projekt zawsze będzie się zmieniał w trakcie procesu wdrażania.

Wszystko wskazuje na to, że podczas egzekwowania reguł biznesowych na pewno należy do ViewModel, wydaje się nam, że prosta konwersja i formatowanie jest rzeczą poglądową. Może to brzmieć jak herezja, ale tak naprawdę nie uważam, że konwersja typu w widoku wymaga w ogóle testów jednostkowych (tak długo testujemy konwertery typów rzeczywistych).

W sumie wspaniała dyskusja, ludzie, z dobrze sformułowanymi, świadomymi opiniami. Dzięki.

+2

Właśnie napisałem to pytanie. +1 – Gishu

Odpowiedz

13

To jest bardzo interesujące pytanie, które nie wydaje mi się, aby zawierało ostateczną odpowiedź, ale zrobię co w mojej mocy, aby wyrzucić tam moje myśli.

Patrząc na wzór MVVM, jak rozumiem, punktem ViewModel jest wystawienie danych w taki sposób, aby View mógł zrozumieć, bez względu na założenia dotyczące sposobu, w jaki widok będzie go używał. Na przykład udawajmy że jesteśmy modelowania prędkości samochodu:

public class CarModel 
{ 
    public int MilesPerHour { get; set; } 
} 

public class CarViewModel 
{ 
    private CarModel _model; 

    public int MilesPerHour 
    { 
     get { return _model.MilesPerHour; } 
     set { _model.MilesPerHour = value; } 
    } 
} 

W powyższym przykładzie mam narażona właściwość jako int, ponieważ to, co jest w modelu. Wady tego masz wymienione w pytaniu, ale główną zaletą jest to, że daje twórcy widoku cenną informację o tym, jak wyświetlić te dane. Pamiętaj, że my (jako twórcy ViewModel) nie wiemy, jak wygląda Widok. Zaangażowanie się w ideę danych jest int View może korzystać z pola tekstowego lub innej kontrolki, która akceptuje tylko liczby (np. Pokrętło), aby wyświetlić informacje. Jeśli powiemy, że zamierzamy sformatować dane w taki sposób, aby uzyskać , pomocne jest to, że View odbiera to ważne mocowanie.

Z drugiej strony pracujemy w prawdziwym świecie. Mamy tendencję do poznania tego, czym jest ten widok. Rzadko podłączamy i odtwarzamy różne widoki na ten sam ViewModel, a dodanie kodu konwersji do ViewModel jest po prostu łatwiejsze. Nie sądzę, że to jest w porządku, ale to nie znaczy, że nie odnajdziesz mojego kodu produkcyjnego za jego pomocą ...

Wreszcie (i jestem pewien, że to wiesz, ale ze względu na uzupełnienia ...) Logika biznesowa powinna być wykonana w ViewModel za pomocą. Jeśli zdecydujemy, że samochód nie powinien przekroczyć 70 mil na godzinę, to nie jest obowiązkiem poglądu, aby to wymusić. Więc nadal będziesz mieć jakiegoś dostawcę błędu, ale w biznesie, a nie na poziomie wyświetlania.


Dobra, może to nie było w końcu ....

Chciałem zająć się komentarze Kent, a moje myśli nie pasował do komentarza.

Oczywiście zasadniczą różnicą między punktem widzenia mojego i Kenta (jak rozumiem) jest to, że czyta ViewModel jako Model Widoku i czytam go jako przedmiot eksponujący Modelowi na Widok. Subtelna różnica, którą muszę przyznać, ale myślę, że wynik jest taki, że nie chcę usuwać informacji dostarczanych przez model, nawet jeśli ułatwia to określony widok, którego używam.

Mój punkt widzenia opiera się na założeniu, że powinieneś być w stanie wymieniać widoki, powinny to być ulotne rzeczy, które mogą się zmieniać w zależności od wymagań dotyczących rozmiaru ekranu, sprzętu, platformy, opóźnień i środowiska. Interesujący jest fakt, że w tej chwili nie potrzebowałem tej funkcji, ani nie widziałem (poza aplikacjami do sprawdzania koncepcji), z której kiedykolwiek korzystałem, ale jeśli zaakceptujemy, że nie będziemy jej używać teraz ani w żadnym momencie w przyszłości i że każdy ViewModel będzie pracował z jednym, i tylko jednym, View, wtedy możemy równie dobrze wrócić do umieszczenia całego kodu w pliku z kodem i całkowicie wyrzucić ViewModel - w końcu jest tak ściśle powiązany, że może i bądź tą samą klasą.

Idealnie chciałbym sytuacji, w której ViewModel może powiedzieć "ta wartość jest int, zawsze będzie int, i można go wyświetlić w każdym razie, co lubisz." Ale możesz dać wszystko z powrotem do mnie i ja Zrobię co w mojej mocy, żeby to pasowało, a jeśli nie, dam ci znać ". Zasadniczo moja właściwość MilesPerHour powinna mieć int getter, ale obiekt ustawiający. Dzięki temu widoki zachowują wszystkie informacje, których potrzebuję, ale nie muszą się martwić o konwersje i sprawdzanie poprawności.

+1

Bardzo dobrze, Martin. Dzięki. –

+0

Mam nadzieję, że wiesz, jak wygląda widok.Jeśli nie, coś poważnie zepsuło się w Twojej współpracy między twórcami a projektantami. Przejęcie odpowiedzialności za określone aktywa nie oznacza, że ​​działamy w próżni - nadal musimy zrozumieć, co robi druga strona. –

+0

Nie wiem, jak wygląda widok, jeśli pracuję w aplikacji, która może być pobierana przez osoby trzecie. Ale nawet poza tym scenariuszem miałem na myśli wzorzec MVVM sugerujący, że w idealnym świecie ViewModel nie powinien nic wiedzieć o Widoku (nawet czy jest to WPF, Webforms czy coś innego). –

5

To jest dobre pytanie i na pewno widzę obie strony dyskusji.

Uważam, że to, czego naprawdę szukasz, to właściwy NumericInputControl, którego możesz użyć w swoim xaml. Zapewni to lepszą wygodę użytkownika, ponieważ użytkownicy nie będą mogli przypadkowo wpisać tekstu w polu liczbowym, a ponieważ kontrola ogranicza wprowadzanie bez sprawdzania poprawności, można zachować bardziej napisany ViewModel.

Nie jestem pewna, jak byś chciała go wdrożyć, wiem, że klasyczne sterowanie pokrętłem/NumericUpDown spada ze względu na to, że nie są przyjazne dla dotyku, ale nie wierzę w to wprowadzenie takiej kontroli naruszy czystość podejścia projektowego lub twoich ViewModels. Otrzymasz numer, który możesz następnie zatwierdzić w zakresie w odpowiednim miejscu, przekazać informacje zwrotne za pośrednictwem IDataErrorInfo jak zwykle i tak dalej. :) Ta technika pozwala uzyskać najlepsze z obu światów bez żadnych rzeczywistych wad (z wyjątkiem tworzenia kontroli numerycznej).

+1

Hm. Proponujesz podział pracy - widok konwertuje do i od poprawnego typu, a w viewmodel sprawdza przekonwertowane dane. To ma sens. –

8

Absolutnie należy w modelu widoku dla wszystkich zwykłych powodów, w tym:

  • Projektanci właścicielem XAML. Czy chcesz, aby projektanci musieli zrozumieć i wdrożyć wymaganą logikę konwersji i sprawdzania poprawności?
  • Testowalność. Czy nie chcesz potwierdzić, że logika konwersji i sprawdzania poprawności działa poprawnie? Jest o wiele trudniejsze, jeśli jest osadzone w widoku.

Z drugiej strony, konwersji, walidacji itd będzie mniej deklaratywne, wyraźny i elastyczne, z punktu widzenia projektanta widoku

myślę, że jest to sprawa dyskusyjna, ponieważ projektant widoku powinien być odpowiedzialny za te rzeczy. Projektant stara się, aby interfejs użytkownika wyglądał i czuł się w określony sposób; to programista implementuje logikę biznesową, w tym logikę konwersji i sprawdzania poprawności.

5

Czy model MVVM ViewModel powinien wykonywać konwersję/weryfikację typu ?

Tak.

Model widoku to warstwa abstrakcji między widokiem a modelem - idealne miejsce do wykonywania konwersji dowolnego typu (zamiast uciążliwych konwerterów wartości). Walidacja powinna bezwzględnie wystąpić jako część modelu widoku.

Stosujemy nasz model widoku, aby obsłużyć konwersje w największym możliwym zakresie dla typów danych. Zmniejsza to potrzebę konwertera wartości do bardzo szczególnych okoliczności. Chcesz pokazać, jaki typ jest najłatwiejszy do wyświetlenia. To działa dobrze.

Jedno konkretne pytanie podniosłeś:

Jeśli, powiedzmy, wartość nienumeryczny jest wpisany w polu tekstowym związanego z własności numerycznej, konwersja zawiedzie, jest nieruchomość nie ustawiać i nigdy nie mamy szansy dostarczyć użytkownikowi odpowiedniej informacji zwrotnej na temat . Gorzej, właściwość zachowuje aktualną wartość , co prowadzi do niezgodności między , co jest wyświetlane w widoku, a tym, co faktycznie jest w ViewModel.

może być obsługiwane przez wystawiania widoku modelu typu jako wartości pustych typu. Powinno to nadal umożliwiać aktualizację źródłowego źródła, nawet jeśli wprowadzono nieprawidłowe dane i przeprowadzić walidację. To działało w podobnej sytuacji jak w przypadku DateTime i selektora daty.

Zachowaj widok jako głupi. Nie mamy oficjalnych projektantów, nasi programiści są nasi projektanci, więc utrzymanie pogląd głupi ma pewne zalety:

  • My (programiści) się zachować nasze zdrowie psychiczne (XAML jest nieco mniej gadatliwy)
  • logiki biznesowej (w tym sprawdzanie poprawności) pozostaje w widoku modelu i może umożliwić testowanie:

Powodzenia!

-Z

0

Albo powinien właściwości ViewModel odsłonić rzeczywiste typy danych, pozostawiając te prace do widoku do obsługi?

  1. Konwersja i szablony są wykonywane w View, ponieważ oba są tylko konwersja values, models i viewmodels do controls! Controls są dostępne tylko wewnątrz View.

  2. Validation odbywa się w ViewModel, ponieważ walidacja odbywa się zgodnie z regułami biznesowymi, a nawet może być wykonywane poprzez wywołanie zdalnej obsługi. Widok nie wie nic o regułach biznesowych, ale potrafi zaprezentować wyniki sprawdzania poprawności.

Jeśli, powiedzmy, wartość numeryczna nie jest wpisany w polu tekstowym związana z właściwością numeryczną

Odpowiednio spreparowane sterowanie numeryczne pole tekstowe nie pozwala użytkownikowi na wejście nie- wartość numeryczna.

Powiązane problemy