Często musimy implementować interfejs INotifyPropertyChanged. Szczególnie w przypadku wykorzystania wzorca MVVM oraz WPF. Najczęściej programiści wykorzystują podstawową implementację i przekazują nazwę parametru jako czysty string np:
if(PropertyChanged!=null) { PropertyChanged(this,new PropertyChangedEventArgs("propName")); }
Wszystko działa bardzo dobrze, dopóki nie zmienimy nazwy właściwości. Przede wszystkim należy wtedy pamiętać o zaktualizowaniu wszystkich wywołań ProperyChanged. Nie możemy ponadto skorzystać ze standardowego narzędzia do refaktoryzacji dostarczonego przez Visual Studio – string nie zostanie zmieniony. Istnieje jednak bardzo proste rozwiązanie, polegające na wykorzystaniu wyrażeń Lambda. Najlepiej rozważmy od razu fragment kodu:
public static class INotifyPropertyChangedExtensions { public static void Raise<T>(this PropertyChangedEventHandler handler,object sender, Expression<Func<T>> expression) { if (handler != null) { var body = propertyExpression.Body as MemberExpression; if (body == null) throw new ArgumentException("'expression' should be a member expression"); var expression = body.Expression as ConstantExpression; if (expression == null) throw new ArgumentException("'expression' body should be a constant expression"); var e = new PropertyChangedEventArgs(body.Member.Name); handler(sender, e); } } }
Powyższa klasa to rozszerzenie do ProperyChangedEventHandler. Sprawdza ona czy jest podpięte jakieś zdarzenie, jeśli tak to odpala je przekazując dynamicznie skonstruowany PropertyChangedEventArgs. Teraz zamiast przekazywać nazwę właściwości w formie stringu, przekazujemy po prostu samą właściwość:
PropertyChanged.Raise(this,()=>this.Price);
Polecam, jeszcze bardziej zautomatyzowanie implementowania INotifyPropertyChanged poprzez wstrzykiwanie odpowiedniego kodu za pomocą np. odpowiedniego zadania MSBuilda i Mono.Cecil. Wtedy w ogóle nie musimy się martwić o to.
Pokazywałem jak to można zrobić w swojej prelekcji o Mono.Cecil – http://pawlos.blogspot.com/2011/09/monocecil-prezentacja.html
Pozdrawiam,
Paweł
@Pawel:
dzieki za info:)
Sam się kiedyś nad tym zastanawiałem, po zgłębieniu tematu zrezygnowałem. Why? Wystarczy zerknąć: http://blog.quantumbitdesigns.com/2010/01/26/mvvm-lambda-vs-inotifypropertychanged-vs-dependencyobject/
@SheGe
Dzieki za link. Faktycznie ciekawe. Lambda jest duza wolniejsza. Nie chce mi sie wiezyc w sumie, chyba sam przeprowadze taki test.
Chociaz z drugiej strony, czy ma to jakiekolwiek znaczenie dla aplikacji biznesowej? Jakos nie chce mi sie wiezyc ze to faktycznie moze spowolnic dzialanie aplikacji.
A tak nawiasem mówiąc to masz malutki błąd zamiast Expression<Func> expression
powinno być
Expression<Func> propertyExpression