DesignMode בWPF
ואחרי שצחקנו, נעבור לחלק האומנותי - איך לקבוע האם הפקד שיצרנו רץ בDesigner כרגע, או באפליקציה רגילה.
כל תחום הDesigner בWPF לא מזכיר את מה שהיה קודם לכן עבור WinForm. הבעיה שלי התחילה בפעם הראשונה שייצרתי פקד בWPF. הפקד אמור היה לשמש אנשי UI בExpression Blend, ז"א - הוא היה צריך להיות מאוד מאוד פשוט. כמה שפחות Properties שזמינים לעריכה וכמה שיותר דברים שהוא ידע לעשות אוטומטית (כמו Docking בתוך Panel וכו').
השלב הראשון בעבודה היה כמובן - לזהות מתי אני בDesigner כדי שאוכל לספק התנהגויות שונות (כמו מסגרת, חלון עריכה מוסדר וביצי פסחא עבור צירופי מקשים מסויימים).
כדי להבין מה חדש בWPF - נתחיל בסקירה של מה שהיה:
בעבר, כל UserControl מימש Property בשם DesignMode, שהחזיר true במידה והפקד היה (באופן מפתיע) בDesigner. במימוש הזה היו שתי בעיות (וחצי):
- לא ניתן היה לקבל סטטוס מדוייק בתוך הConstructor של הפקד. זאת משום שProperty קיבל ערך רק אחרי שהDesigner בצע Deserialization לקוד שכתוב בתוך הInitializeComponents (אגב, אני מקווה לכתוב בעתיד פוסט על הסריאליזציה שמתבצעת בInitializeComponents).
- Nested Controls שנוצרו תחת פקד אחר לא ידעו להחזיר את מצבם.
- חצי בעיה נוספת - בעבר, הDesigner היחיד היה הIDE של VS. בWPF אנחנו לראשונה נתקלים במצב בו יש יותר מDesigner אחד (Expression, VS בתור התחלה). מה קורה אם אני רוצה לדעת בדיוק באיזה Designer אני עובד ולא רק האם אני נמצא באחד?
כך עשינו זאת בWinForms:
קוד:
public class CustomButton : Button
{
public CustomButton()
{
if (this.DeisgnMode)
{
this.Text= "In Design Mode";
}
else
{
this.Text= "Runtime";
}
}
}
הפתרון שהומצא עבור WPF באחד הCTPים הראשונים:
הפתרון הראשוני שנמצא לבעיות שהוזכרו לעיל היה... לסבך את העסק. מחד גיסא, כמו שהתבקש - הפרמטר הפך לגלובאלי, ז"א - בכל מצב ניתן היה לחלץ את מצב הריצה של התוכנית מהAppDomain. מאידך גיסא - זה הוחזר כDependencyProperty שזה קצת איכסה. (אגב, גם בWinForms ניתן לקבל את הפרמטר הזה גלובאלית, דרך הLicenseManager. אם תהיה דרישה, אכתוב גם על זה פוסט בעתיד).
כך זה היה נראה אלמלא תושיה של אחד הטוקבקיסטים בבלוג של UrbanPotato:
קוד:
bool IsDesignMode {
get {
DependencyProperty isDesignModeProperty = (DependencyProperty)AppDomain.CurrentDomain.GetData(“IsDesignModeProperty”);
return isDesignModeProperty == null ? false : true.Equals(isDesignModeProperty.GetValue(this));
}
}
ומכאן, הדרך כבר הייתה סלולה לפתרון שזמין היום:
תחת הComponentModel הוכנסה המחלקה DesignerProperties שמציעה לנו בין היתר את GetIsInDesignMode. הפונקציה תחזיר bool עם התשובה.
וכך זה ייראה מהיום והלאה (או לפחות, עד הפעם הבאה שמיקרוסופט תעצור לשימון צירים):
קוד:
public class CustomButton : Button
{
public CustomButton()
{
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
Content = "In Design Mode";
}
else
{
Content = "Runtime";
}
}
}
את ההודעה כתבתי במקור בפורום תיכנות אותו אני מנהל באתר פרש (שגם אותו אני מנהל).