2010-11-11 67 views
15

Staramy się wymyślić walidację w mvvm przeprowadzając walidację w logice biznesowej lub modelu. mam wdrożony zatwierdzić typu wyjątku w naszej logiki biznesowej - uproszczony schemat można znaleźć tutaj: alt textMVVM - Walidacja

Jeśli mamy partii wejść, które są od siebie niezależne, nie ma problemu, wyjątek jest wyrzucany, pole tekstowe przechwytuje go jako znak, że graniczy z czerwonym dla każdego błędnego wejścia. Jednak gdy mamy wartości zależne, mamy kłopoty. np.

  • Value1 i WartoÊç2 w modelu nie muszą być takie same, więc mamy funkcję sprawdzania poprawności w każdym z tych, którzy szukają wartości równa się i rzucić wyjątek, jeśli tak się stanie

  • teraz jeśli ustawimy wartość 1 na 0 i wartość 2 na 1 wszystko będzie dobrze

  • Wartość 1 zostanie ustawiona w GUI na 1 -> ta zostanie zaznaczona na czerwono, ponieważ sprawdzanie poprawności innych wartości nie zostanie uruchomione, więc wartość 2 w GUI nie jest oznaczone jako wadliwe

  • WartoÊç2 zostanie ustawiona na 2 w GUI, teraz doszliśmy poprawny stan, ale tylko WartoÊç2 zostanie potwierdzone, więc Value1 nadal jest oznaczony jako uszkodzony

Czy istnieje wspólny wzór, aby rozwiązać ten problem? nie chcemy wprowadzać zależności w GUI między dwoma polami tekstowymi, ponieważ logika ta powinna być obecna tylko w warstwie logiki biznesowej.

Zamiast wdrażania zatwierdzić wyjątku można też zaimplementować interfejs IDataErrorInfo, ale problem nadal istnieje, nie ma sposobu, aby zmusić zależności od wartości ponownie potwierdzić swoje wartości, przynajmniej nie widzę :)

Każda pomocy ocenia się

cheers, manni


[czyszczenia, usuwa unecessary krok]


15.11.2010 - Part2

ok, duży przemyślane tutaj, jedziemy z businesslogic kondygnacji. tutaj jest nasza obecna planowana konfiguracja: alt text (obraz jest nieco mały skalowany tutaj, proszę otworzyć go w osobnym oknie, aby pokazać go w pełnym rozmiarze) wszystko jest mniej lub bardziej wyraźne, z wyjątkiem tego, jak powiadomić wszystkie modele widoków/modeluj klony różnych edytorów, jeśli zmieni się model danych w ramach logiki biznesowej. jednym ze sposobów jest śledzenie sklonowanych modeli w logice biznesowej, która je tworzy. Gdy model danych zostanie zmieniony przy użyciu logiki biznesowej commit(), wszystkie inne zarejestrowane klony modelu mogą zostać powiadomione o zmianach i dalej je propagować. Ewentualnie logika biznesowa może opublikować wydarzenie, do którego subskrybowane są wszystkie modele widokowe, aby również mogły one uzyskać zmiany - czy ktoś mógłby dać mi wskazówkę, co jest lepsze?

Jeszcze raz dziękuję za pomoc, przepraszam, że jestem tak umysł zablokowany;)

+0

Dlaczego wartości właściwości ustawienia maszyny wirtualnej znajdują się w warstwie biznesowej? To wydaje się być przyczyną niektórych twoich problemów. Wydaje się, że wszyscy (jak się wydaje) mają nieco inną interpretację tego, co oznacza MVVM, ale model IMHO jest kombinacją modelu danych i kontrolera, więc posiada nadzbiór danych w VM i koordynuje dostęp do usług sieciowych/repozytoriów/etc . Tak więc istniejąca warstwa biznesowa powinna zostać włączona do bieżącego modelu lub ewentualnie przeniesiona do modelu po (na przykład po drugiej stronie granicy WCF). – slugster

+0

Myślimy o zwijaniu modelu (który jest naszym modelem danych) i BusinessLogic w jedną warstwę, co w istocie oznacza to, co rozumiem poprawnie. ale nadal myślę, że vm nie powinien zawierać sprawdzania poprawności. Ale nadal problem z przekazywaniem ciągów trwa. Przesuwając logikę biznesową na drugą stronę granicy wcf, czy oznacza to, że cały model jest po prostu niemym posiadaczem danych, który może być edytowany i jest przesyłany jako całość do logiki biznesowej i tam oceniany? czy masz jakieś linki dotyczące korzystania z granicy wcf i podziału? dzięki za pomoc – manni

+0

Absolutnie dokonujesz sprawdzenia poprawności w maszynie wirtualnej, ale jest to prosta walidacja, np. * Hasło jest dłuższe niż 6 znaków * lub * adres e-mail jest prawidłowy *. Możesz oddzielić swoją logikę biznesową od modelu, rozważ użycie metody n-warstwy dla modelu-> logiki biznesowej-> repozytorium danych (często BL i warstwy danych są włączone do usługi internetowej, ale nie musi to być, jeśli korzystasz tylko z lokalnej bazy danych). Posiadanie BL w modelu jest nadal lepszym rozwiązaniem niż to, co obecnie masz. – slugster

Odpowiedz

15

Można rozważyć przy użyciu interfejsu System.ComponentModel.IDataErrorInfo.To bardzo wygodny interfejs daje możliwość:

  • zrobić walidację w MVVM sposób zgodny
  • zrobić niestandardową walidacji dla danego pola (walidacja mógł sprawdzić kilka wartości, jeśli chcesz go)
  • wiążą twój interfejs użytkownika na błędy sprawdzania poprawności

Implementujesz IDataErrorInfo na swoim viewmodelu (lub nawet wirtualnie w swojej bazie modelu widoku i zastępujesz go w pochodnych modelach widoku). Ze względu na charakter wiązania danych, wartości, które należy sprawdzić, znajdują się w modelu widoku i mogę przetestować dowolną ich kombinację. Oczywiście nadal masz sprawdzanie poprawności w warstwie biznesowej, ale nie musisz już robić podróży do warstwy biznesowej (lub Modelu) tylko po to, aby przeprowadzić jakąś walidację.

Oto krótki przykład z ekranu (WPF), która gromadzi pewne dane użytkownika i robi podstawowe walidacji na nich:

kodu C#:

#region IDataErrorInfo Members 

    /// <summary> 
    /// Gets an error message indicating what is wrong with this object. 
    /// </summary> 
    /// <value></value> 
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns> 
    public override string Error 
    { 
     get 
     { 
      return this["UserCode"] + this["UserName"] + this["Password"] + this["ConfirmedPassword"] + this["EmailAddress"]; 
     } 
    } 

    /// <summary> 
    /// Gets the <see cref="System.String"/> with the specified column name. 
    /// </summary> 
    /// <value></value> 
    public override string this[string columnName] 
    { 
     get 
     { 
      switch (columnName) 
      { 
       case "UserCode": 
        if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 20) 
         return "User Code must be less than or equal to 20 characters"; 
        break; 

       case "UserName": 
        if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 60) 
         return "User Name must be less than or equal to 60 characters"; 
        break; 

       case "Password": 
        if (!string.IsNullOrEmpty(Password) && Password.Length > 60) 
         return "Password must be less than or equal to 60 characters"; 
        break; 

       case "ConfirmedPassword": 
        if (Password != ConfirmedPassword) 
         return Properties.Resources.ErrorMessage_Password_ConfirmedPasswordDoesntMatch; 
        break; 

       case "EmailAddress": 
        if (!string.IsNullOrEmpty(EmailAddress)) 
        { 
         var r = new Regex(_emailRegex); 
         if (!r.IsMatch(EmailAddress)) 
          return Properties.Resources.ErrorMessage_Email_InvalidEmailFormat; 
        } 
        break; 
      } 
      return string.Empty; 
     } 
    } 

    #endregion 

A oto znaczników XAML dla dwóch te pola tekstowe na stronie (uwaga zwłaszcza ValidatesOnDataErrors i ValidatesOnExceptions właściwości w Text wiązaniami):

<TextBox Name="UserCodeTextBox" 
     Text="{Binding UserCode, 
       Mode=TwoWay, 
       UpdateSourceTrigger=PropertyChanged, 
       ValidatesOnDataErrors=True, 
       ValidatesOnExceptions=True, 
       NotifyOnSourceUpdated=True, 
       NotifyOnTargetUpdated=True}" 
     GotFocus="Input_GotFocus" 
     VerticalAlignment="Top" 
     Margin="165,0,150,0" 
     CharacterCasing="Upper" 
     /> 

<TextBox Name="UserNameTextBox" 
     Text="{Binding UserName, 
       Mode=TwoWay, 
       UpdateSourceTrigger=PropertyChanged, 
       ValidatesOnDataErrors=True, 
       ValidatesOnExceptions=True, 
       NotifyOnSourceUpdated=True, 
       NotifyOnTargetUpdated=True}" 
     GotFocus="Input_GotFocus" 
     VerticalAlignment="Top" 
     Margin="165,30,0,0" 
     /> 
+0

dzięki za szczegółową odpowiedź. to jest zupełnie różne od podejścia wyjątków, ponieważ z interfejsem IDataErrorInfo ty zasadniczo - ustawić wartość - Sprawdź, czy obiekt jest w poprawnym stanie Oznacza to, że pomiędzy nimi można uzyskać obiekt z nieprawidłowym stanie to jest w porządku, jeśli masz przycisk zatwierdzania/zapisywania i pracujesz na klonie od modelu, ale przejście bezpośrednio do modelu z niepoprawnym stanem jest nieco niebezpieczne – manni

+0

@user Dane nigdy nie uderzą modelu widoku w tym przykładzie jeśli walidacja nie powiedzie się. Powiązanie najpierw sprawdzi, a następnie odrzuci dane, zanim zostanie powiązane z modelem widoku. –

+1

@josh: od linii ta metoda [string] przyjmuje nazwę właściwości i uzyskuje dostęp do jej własnego członka o tej nazwie, ten członek musi mieć nową niepoprawną wartość, w przeciwnym razie czek nie może zostać dokonany (i zostanie wykonany do starego wartość) - czy coś tu brakuje? – manni

0

Czy istnieje wspólny wzorzec do rozwiązania tego problemu? nie chcemy wprowadzać zależności w GUI między dwoma polami tekstowymi, ponieważ logika ta powinna być obecna tylko w warstwie logiki biznesowej.

  1. Value1 i Value2 są współzależne ze względu na stan „Value1 i WartoÊç2 w modelu nie muszą być takie same”.

  2. Oznacza to, że gdy Value2 zmienia się, zmienia się także Value1 i vice werset! Rzeczywiście, gdy zmienia się Value2, wynik sprawdzania poprawności zmienia się, ale jest zbliżony do poprzedniej instrukcji.

  3. Value1 i Value2 ustawiaczy musi powiadomić o zarówno Value1 i Value2 zmiany własności.

  4. Widok musi ponownie odczytać i ponownie potwierdzić obie wartości oraz wyczyścić wadliwy znak.

  5. Nie jestem pewien, czy zrobi to WPF, jeśli stwierdzi, że zdarzenie powiadomienia zostało podniesione, ale wartość faktycznie nie uległa zmianie.