Una soluzione recente sono venuto in mente è per incapsulare la logica dell'evento spedizione in una classe dedicata.
la classe ha un metodo pubblico chiamato Handle
che ha la stessa firma del delegato PropertyChangedEventHandler
significa che può essere sottoscritto al PropertyChanged
caso di qualsiasi classe che implementa l'interfaccia INotifyPropertyChanged
.
La classe accetta delegati come lo spesso utilizzato DelegateCommand
utilizzato dalla maggior parte delle implementazioni WPF, il che significa che può essere utilizzato senza dover creare sottoclassi.
La classe si presenta così:
public class PropertyChangedHandler
{
private readonly Action<string> handler;
private readonly Predicate<string> condition;
private readonly IEnumerable<string> properties;
public PropertyChangedHandler(Action<string> handler,
Predicate<string> condition, IEnumerable<string> properties)
{
this.handler = handler;
this.condition = condition;
this.properties = properties;
}
public void Handle(object sender, PropertyChangedEventArgs e)
{
string property = e.PropertyName ?? string.Empty;
if (this.Observes(property) && this.ShouldHandle(property))
{
handler(property);
}
}
private bool ShouldHandle(string property)
{
return condition == null ? true : condition(property);
}
private bool Observes(string property)
{
return string.IsNullOrEmpty(property) ? true :
!properties.Any() ? true : properties.Contains(property);
}
}
È possibile quindi registrare un gestore di eventi cambiato proprietà come questa:
var eventHandler = new PropertyChangedHandler(
handler: p => { /* event handler logic... */ },
condition: p => { /* determine if handler is invoked... */ },
properties: new string[] { "Foo", "Bar" }
);
aViewModel.PropertyChanged += eventHandler.Handle;
Il PropertyChangedHandler
si occupa di verificare la PropertyName
del PropertyChangedEventArgs
e assicura che handler
viene richiamato dalle modifiche alle proprietà corrette.
Si noti che PropertyChangedHandler accetta anche un predicato in modo che il delegato del gestore possa essere inviato condizionatamente. La classe consente inoltre di specificare più proprietà in modo che un singolo gestore possa essere associato a più proprietà contemporaneamente.
Questo può essere facilmente esteso con alcune estensioni metodi per più conveniente di registrazione del gestore, che ti permette di creare il gestore di eventi e sottoscrivere l'evento PropertyChanged
in una singola chiamata di metodo e specificare le proprietà usando espressioni invece di stringhe per realizzare qualcosa che assomiglia a questo:
aViewModel.OnPropertyChanged(
handler: p => handlerMethod(),
condition: p => handlerCondition,
properties: aViewModel.GetProperties(
p => p.Foo,
p => p.Bar,
p => p.Baz
)
);
questo è fondamentalmente dicendo che quando uno le proprietà Foo
, Bar
o Baz
cambiamento sarà richiamato handlerMethod
se handlerCondition
è vero.
Sono previsti sovraccarichi del metodo OnPropertychanged
per coprire i diversi requisiti di registrazione degli eventi.
Se, ad esempio, si desidera registrare un gestore che viene chiamato per qualsiasi proprietà evento modificato e viene sempre eseguita si può semplicemente effettuare le seguenti operazioni:
aViewModel.OnPropertyChanged(p => handlerMethod());
Se, ad esempio, si desidera registrare un gestore che viene sempre eseguito, ma solo per un singolo specifica modifica della proprietà è possibile effettuare le seguenti operazioni:
aViewModel.OnPropertyChanged(
handler: p => handlerMethod(),
properties: aViewModel.GetProperties(p => p.Foo)
);
ho trovato questo approccio molto utile quando si scrivono applicazioni WPF MVVM. Immagina di avere uno scenario in cui vuoi invalidare un comando quando cambia una delle tre proprietà. Utilizzando il metodo normale si dovrebbe fare qualcosa di simile:
void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Foo":
case "Bar":
case "Baz":
FooBarBazCommand.Invalidate();
break;
....
}
}
Se si modifica il nome di una qualsiasi delle proprietà ViewModel che sarà necessario ricordarsi di aggiornare il gestore di eventi per selezionare le proprietà corrette.
Uso della classe PropertyChangedHandler
specificato sopra si può ottenere lo stesso risultato con il seguente:
aViewModel.OnPropertyChanged(
handler: p => FooBarBazCommand.Invalidate(),
properties: aViewModel.GetProperties(
p => p.Foo,
p => p.Bar,
p => p.Baz
)
);
Questo ha ora a tempo di compilazione di sicurezza in modo Se una qualsiasi delle proprietà ViewModel vengono rinominati il programma non riuscirà a compilare.
(Anche se, francamente, se si vuole veramente adeguata sicurezza tipo, forse si dovrebbe prendere in considerazione non usando 'PropertyChangedEventArgs' a tutti e invece dichiarando uno proprio che contiene l'oggetto' PropertyInfo' invece di una stringa.) – Timwi