Wednesday, October 16, 2013

PropertyChanged – למתקדמים WPF

כל מפתח WPF יודע מה עושה INotifyPropertyChanged וסביר להניח שגם מה עומד מאחורי המנגנון, ומן הסתם יודע גם מה זה Observer Pattern.

הפעם נלך 2 צעדים קדימה..

נתחיל בתזכורת: כשאני מממש על אובייקט את האינטרפייס הנ"ל אני מחוייב להחזיק Event שנראה כך:

   1: public class ViewModel : INotifyPropertyChanged
   2:     {
   3:         public event PropertyChangedEventHandler PropertyChanged;
   4:     }                                                                          
   5: public int MyProperty
   6:     {
   7:      get { return myVar; }
   8:      set
   9:        { 
  10:          myVar = value;
  11:          PropertyChanged(this, new PropertyChangedEventArgs("MyProperty"));
  12:         }
  13:  
  14: }                                                                   

יפה, אם נרצה להשתכלל מעט נעשה את המימוש הבא (פחות או יותר) ונרגיש סופר חכמים.

   1: private void RaisPropertyChanged(string properytyName)
   2: {
   3:    if (PropertyChanged != null)
   4:    {
   5:     PropertyChanged(this, new PropertyChangedEventArgs(properytyName));
   6:    }
   7: }                                                                      

ואז אנחנו מעבירים נתונים של שם המשתנה בלבד. אבל זה עדיין מאוד בעייתי, כי טעות קטנה בצורת האיות של הProperty Name מאבדת את התקשורת ואפילו לא נקבל חיווי!

אז מי שיצא לו לעבוד עם תשתיות גדולות כמו Caliburn או Prism בטח נתקל במימוש ה"מגניב" שבו אתה שולח דלגייט ומישהו טורח להוציא את הערך ולעדכן על השינויים, ואז כמובן אין חשש לטעויות בשמות.

אז איך דבר כזה עובד? זה פשוט מאוד ברגע שרואים את המימוש !

נתבונן רגע בקוד הבא: (אפשר גם להעתיק ולהריץ..)

   1: protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> expression)
   2:         {
   3:             if (expression == null)
   4:                 throw new ArgumentNullException("Expression fault");
   5:             MemberExpression body = expression.Body as MemberExpression;
   6:             if (body == null)
   7:                 throw new ArgumentException("The property must be valid");
   8:             if (PropertyChanged != null)
   9:             {
  10:                 PropertyChanged(this, new PropertyChangedEventArgs(body.Member.Name));
  11:             }
  12:         }

מה שעושה הפונקציה זה לקבל דלגייט גנרי שיודע להוציא משדה פעולה את השם של המתודה

במקרה הזה מפרקת את שם הפרופרטי שמחזיק את הפעולה ומחזירה אותו למימוש הפנימי.

Expression זה קלאס מתוך ספריית LINQ ומאחר שפרופרטיז הם למעשה פונקציות אז אנו מעבירים את הפרופרטי בתור דלגייט ומחלצים את שם ה"דלגייט" בזמן ריצה.

זהו! טריקים לכולם !! נשתמש בזה בצורה הרגילה, נניח כך:

   1: private string m_test;
   2:       public string Test
   3:       {
   4:           get { return m_test; }
   5:           set
   6:           {
   7:               m_test = value;
   8:               RaisePropertyChanged(() => Test);
   9:           }
  10:       }                                                                      

נתראה..

QR: Inline images 1