2011-12-06 12 views
5

Mam problem z sprawdzaniem poprawności między wieloma polami. Na przykład - Mam ViewModel o nazwie RangeDateViewModel, który zawiera 2 wystąpienia klasy o nazwie DateViewModel, każdy z nich reprezentuje odpowiednio datę rozpoczęcia i datę zakończenia.Sprawdzanie poprawności między wieloma polami na różnych poziomach

więc moja oprawa wygląda następująco -

<TextBox Text="{Binding StartDate.Date, ValidateOnDataError=True}"> 
<TextBox Text="{Binding EndDate.Date, ValidateOnDataError=True}"> 

Moja klasa RangeDateViewModel implementuje interfejs IDataErrorInfo. W moim planem, RangeDateViewModel by potwierdzić, że data rozpoczęcia jest przed terminem końcowym, stosując logikę walidacji w IDataErrorInfo [ „propertyName”] funkcji tak -

public string this[string columnName] 
    { 
     get 
     { 
      return ValidationError(); 
     } 
    } 

Problemem jest to, że nigdy nie jest podczas wywoływania, zamiast tego wywoływane są właściwości IDataErrorInfo, które znajdują się w każdej z klas DateViewModel.

Przypuszczam, że dzieje się tak dlatego, że właściwość bound nie znajduje się na tym samym poziomie co RangeDateViewModel, ale zamiast tego znajduje się w podrzędnej funkcji DateViewModel.

Myślę, że moja potrzeba jest dość prosta i musi istnieć łatwe rozwiązanie tego problemu. Próbowałem używać ValidationRules zamiast IDataErrorInfo, ale wtedy miałbym problemy z powiadomieniem ViewModel o aktualnym statusie sprawdzania poprawności z ValidationRules.

Odpowiedz

1

Spróbuj użyć następujące podejście:

  1. Create a DataTemplate ™ dla DateViewModel:

    <DataTemplate DataType="{x:Type ViewModels:DateViewModel}"> 
        <TextBox Text="{Binding Date}"> 
    </DataTemplate> 
    
  2. Bind instancje tego ViewModel do ContentControl i ustawić ValidateOnDataError do true na tym oprawa:

    <ContentControl Content="{Binding StartDate, ValidateOnDataError=True}" /> 
    <ContentControl Content="{Binding EndDate, ValidateOnDataError=True}" /> 
    
  3. W RangeDateViewModel subskrybować zdarzenie PropertyChanged z StartDate i EndDate i gdy podniesiona, podnieść PropertyChanged wydarzenie StartDate/EndDate:

    StartDate.PropertyChanged += (s, e) => InvokePropertyChanged("StartDate"); 
    EndDate.PropertyChanged += (s, e) => InvokePropertyChanged("EndDate"); 
    
+0

Dzięki Daniel! Próbowałem tego, co sugerowałeś, ale najwyraźniej wciąż nie jest wystarczająco dobry. Właściwość IDataErrorInfo rzeczywiście uzyskuje dostęp, ale tylko podczas inicjowania szablonu, a nie później, gdy rzeczywiste dane zostaną zmienione. Domyślam się, że to dlatego, że StartDate i EndDate są obiektami złożonymi, że same nie są zmieniane, ale właściwości wewnątrz nich, a to nie jest wystarczająca forma do podniesienia PropertyChanged. Może powinienem jakoś podnieść wydarzenie, gdy zmieni się właściwości wewnętrznej daty? – Dror

+0

@Dror: Masz rację. Zobacz krok trzeci w zaktualizowanej odpowiedzi. –

+0

Jeszcze raz dziękuję Daniel! To zadziałało, chociaż wciąż mam jeszcze jeden drobny problem, z którym się borykam. Dzięki temu rozwiązaniu wynikiem są dwie kontrolki zaznaczone na czerwono, gdy wartość jest nieważna. Chciałbym, aby zamiast zaznaczonych na czerwono, Stackpanel, który przechowuje te dwa pola, zostanie oznaczony jako przeczytany. Korzystnie te dwa pola nie będą zaznaczone, ale nie jest to koniecznością. Próbowałem zastosować DataTrigger na właściwości bool na RangeDateViewModel o nazwie "HasErrors", który ustawi "Validation.HasError" na true, ale niestety jest to właściwość tylko do odczytu. Mam nadzieję, że pomożecie mi w tej kwestii. – Dror

1

miałem problemu public string this[string columnName] po prostu nie nazwie po prostu inna tydzień.

Rozwiązanie było proste. Wiązanie silnika powiązania WPF nie może być zgodne z zagnieżdżeniem moich ViewModels.

Przypuszczałem, że muszę wdrożyć właściwość w ViewModel, który jest obecny DataContext, ale zamiast musi być wdrożone w ViewModel, który jest związany z kontrolą.

przykład:

<TextBox Text="{Binding Path=ProductViewModel.DescriptionViewModel.ProductName, 
            Mode=TwoWay, 
            ValidatesOnDataErrors=True, 
            NotifyOnValidationError=True}" /> 

tutaj DescriptionViewModel jest klasa zawiera własności wiążące.IDataErrorInfo musi być zaimplementowany w tej klasie (nie w ProductViewModel lub innej klasie w górę hierarchii, która może go zawierać) wtedy wszystko będzie działać poprawnie.

+0

Witaj Sensei, dzięki za komentarz. Mam świadomość, że IDataErrorInfo działa poprawnie, gdy jest zaimplementowany w niższej klasie w hierarchii powiązań, ale mam z tym 2 problemy. 1 - Mam dwie klasy zaangażowane w logikę walidacji, ale każda z tych klas niższego poziomu nie zna się nawzajem. 2 - Nie chcę, aby jedno z pól było zaznaczone na czerwono, jeśli wartość jest nieważna. Chcę, aby cała kontrola została zaznaczona na czerwono. – Dror

Powiązane problemy