Questo è in risposta a un commento ho lasciato . Spero che questo risponda alla tua domanda, Shimmy. Basta commentare, e lo accorgerò o lo rimuoverò se non risponde alla tua domanda.
Avrete bisogno di entrambe le interfacce INotifyPropertyChanging e INotifyPropertyChanged da implementare sulla vostra classe (a meno che non si tratti di qualcosa come un oggetto framework entità, che credo implementi questi internamente).
E prima di impostare un valore su questa proprietà, è necessario generare l'evento NotifyPropertyChanging.PropertyChanging, utilizzando il nome della proprietà nel costruttore PropertyChangingEventArgs.
E dopo aver impostato questo valore è necessario generare l'evento NofityPropertyChanged.PropertyChanged, utilizzando nuovamente il nome della proprietà che viene generato nel costruttore PropertyChangedEventArgs.
Quindi è necessario gestire gli eventi PropertyChanging e PropertyChanged. Nell'evento PropertyChanging, è necessario memorizzare il valore nella cache. Nell'evento PropertyChanged, puoi confrontare e generare un'eccezione.
Per ottenere la proprietà da Argomenti PropertyChanging/PropertyChanged, è necessario utilizzare la rilettura.
// 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
Notate come sto usando PreventRecursion, che è un valore booleano Ho dimenticato di aggiungere sopra questi metodi? Quando si ripristina la proprietà sul valore precedente, questi eventi verranno richiamati.
tl; dr
Ora si potrebbe ricavare un singolo evento che eredita da INotifyPropertyChanged, ma utilizza un argomento che tiene un oggetto che rappresenta il valore precedente, nonché nome della proprietà.E ciò ridurrebbe il numero di eventi sparati a uno, ha funzionalità simili e ha retrocompatibilità con INotifyPropertyChanged.
Ma se si desidera gestire qualcosa prima che la proprietà venga impostata (diciamo che la proprietà esegue una modifica irreversibile o è necessario impostare altre proprietà prima di impostare quella variabile, altrimenti verrà generata un'eccezione) non sarà possibile Fai quello.
Nel complesso, questo metodo è un modo molto vecchio di fare le cose. Vorrei prendere la risposta di Poker Villian e avere dati non validi che possono essere inseriti. Ma non consentire il salvataggio in un database.
Entity Framework ha un codice eccellente per la convalida. Aggiungi la convalida alle tue proprietà tramite attributi. E poi si occupa del lavoro di elaborazione di quegli attributi. Quindi è possibile creare una proprietà denominata IsValid, che chiama la convalida specifica di Entity Framework. Distingue anche gli errori di campo (come digitare caratteri errati o avere una stringa troppo lunga) e errori di classe (come mancare dati o chiavi in conflitto).
Quindi è possibile associare IsValid alla convalida dei controlli e visualizzeranno una bolla rossa quando vengono immessi dati non validi. Oppure potresti semplicemente implementare la convalida IsValid da solo. Ma se IsValid è falso, l'evento SaveChanges dovrebbe annullare il salvataggio.
btw. Il codice fornito non verrà compilato ed è solo pseudocodice (miscelazione di vb e C#). Ma credo che sia molto più descrittivo di C# da solo - mostrando esattamente ciò che viene gestito.
PropertyChangingEventArgs non ha alcuna relazione con CancelEventArgs. Hanno tempi che devono essere utilizzati esclusivamente per scopi diversi. Costringere l'ereditarietà causerebbe complicazione e frustrazione non necessarie (accoppiandoli strettamente). C'è PropertyChangingEvent e PropertyChangedEvent e ritengo che soddisfino le funzionalità desiderate senza che vengano apportate modifiche (per non parlare del fatto che interromperà la compatibilità da .NET 1.1 a .NET 4.0). – TamusJRoyce
@TamusJRoyce, OK, sono d'accordo, non dovrebbe ereditare da 'CancelEventArgs', ma quello che dovrebbe fare è la mia altra richiesta che fornisce il valore candidato (il modo più semplice per ottenerlo è ottenere gli attributi del metodo corrente con un valore significativo ammontare del costo della prestazione). – Shimmy