To w odpowiedzi na komentarz zostawiłem . Mam nadzieję, że to odpowiada na twoje pytanie, Shimmy. Po prostu skomentuj, a skracam lub usuwam, jeśli nie odpowiada na twoje pytanie.
Potrzebne będą interfejsy INotifyPropertyChanging i INotifyPropertyChanged, które zostaną zaimplementowane w klasie (chyba że jest to coś w rodzaju obiektu struktury encji, który moim zdaniem implementuje je wewnętrznie).
Przed ustawieniem wartości tej właściwości należy podnieść wartość zdarzenia NotifyPropertyChanging.PropertyChanging, używając nazwy właściwości w konstruktorze PropertyChangingEventArgs.
Po ustawieniu tej wartości należy podnieść zdarzenie NofityPropertyChanged.PropertyChanged, ponownie używając nazwy właściwości, która jest wywoływana w konstruktorze PropertyChangedEventArgs.
Następnie należy obsłużyć zdarzenia PropertyChanging i PropertyChanged. W zdarzeniu PropertyChanging należy buforować wartość. W zdarzeniu PropertyChanged można porównać i wyrzucić wyjątek.
Aby uzyskać właściwość z argumentów zdarzenia PropertyChanging/PropertyChanged, należy użyć metody relfect.
// PropertyName is the key, and the PropertyValue is the value.
Dictionary <string, object> propertyDict = new Dictionary<object, object>();
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanging(sender As object, e As PropertyChangingEventArgs) Handles Foo.PropertyChanging
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it checks if e.PropertyName already exists.
propertyDict.Add(e.PropertyName, propertyValue);
} // End PropertyChanging() Event
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanged(sender As object, e As PropertyChangedEventArgs) Handles Foo.PropertyChanged
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it makes sure e.PropertyName exists.
object oldValue = propertyDict(e.PropertyName);
object newValue = propertyValue;
// No longer needed.
propertyDict.Remove(e.PropertyName);
if (/* some condition */)
{
try {
preventRecursion = true;
info.SetValue(oldValue, null);
Throw New Exception();
} finally {
preventRecursion = false;
} // End try
} // End if
} // End PropertyChanging() Event
Zauważ, jak używam PreventRecursion, który jest boolean Zapomniałem dodać powyżej tych metod? Po przywróceniu właściwości do poprzedniej wartości zdarzenia te zostaną przywołane.
tl; dr
Teraz można czerpać pojedynczego zdarzenia, które dziedziczy INotifyPropertyChanged, ale używa argumentu, który posiada obiekt reprezentujący poprzednią wartość, jak nazwa właściwości.A to ograniczyłoby liczbę zdarzeń uruchamianych do jednego, mają podobną funkcjonalność i mają wsteczną kompatybilność z INotifyPropertyChanged.
Ale jeśli chcesz zająć się czymkolwiek, zanim właściwość zostanie ustawiona (powiedzmy, że właściwość powoduje nieodwracalną zmianę lub musisz ustawić inne właściwości przed ustawieniem tej zmiennej, w przeciwnym razie zostanie zgłoszony wyjątek) nie będziesz w stanie Zrób to.
Ogólnie rzecz biorąc, ta metoda jest bardzo starym sposobem robienia rzeczy. Chciałbym wziąć odpowiedź od Poker Villiana i podać nieprawidłowe dane. Ale nie zezwalaj na zapisywanie do bazy danych.
Entity Framework ma znakomity kod do walidacji. Dodajesz walidację do swoich właściwości za pomocą atrybutów. A potem dba o pracę przetwarzania tych atrybutów. Następnie możesz utworzyć właściwość o nazwie IsValid, która wywołuje specyficzne sprawdzanie Entity Framework. Rozróżnia także błędy w polu (np. Wpisywanie niewłaściwych znaków lub zbyt długi ciąg znaków) oraz błędy klas (np. Brakujące dane lub klucze powodujące konflikt).
Następnie można powiązać IsValid z kontrolą walidacji i wyświetlają czerwoną bańkę podczas wprowadzania nieprawidłowych danych. Lub możesz sam wdrożyć weryfikację IsValid. Ale jeśli IsValid ma wartość false, zdarzenie SaveChanges będzie musiało anulować zapisywanie.
btw. Podany kod nie zostanie skompilowany i jest tylko pseudokodami (mieszanie vb i C#). Uważam jednak, że jest on znacznie bardziej opisowy niż samo C# - pokazuje dokładnie to, co jest obsługiwane.
PropertyChangingEventArgs nie ma związku z CancelEventArgs. Mają czasy, w których muszą być używane wyłącznie do różnych celów. Wymuszenie dziedziczenia spowodowałoby niepotrzebne komplikacje i frustrację (ścisłe połączenie ich ze sobą). Istnieje PropertyChangingEvent i PropertyChangedEvent i uważam, że spełniają one pożądaną funkcjonalność bez wprowadzania w nich zmian (nie wspominając o tym, że przełamie kompatybilność .NET 1.1 z .NET 4.0). – TamusJRoyce
@TamusJRoyce, OK, zgadzam się, nie powinien on dziedziczyć po 'CancelEventArgs', ale to, co powinien zrobić, to moja druga prośba, która podaje wartość kandydata (którą można łatwo zdobyć, pobierając aktualne atrybuty metody ze znaczącym kwota kosztów wykonania). – Shimmy