יצירת Custom Controls - חלק ב' - Properties & Exceptions
פוסט זה הוא השני בסדרת הפוסטים על יצירת Custom Controls. הבסיס ליצירת Custom Controls הוסבר בפוסט הראשון בסדרה.
בפוסט זה אתמקד בנושא ה - Properties ו - Exceptions.
בפוסט זה ניצור פקד שמטרתו להציג שעה כלשהי (נניח השעה שבה פורום כלשהו התעדכן) בהתאם לאיזור הזמן של המשתמש. לצורך העניין נקרא לפקד הזה TimeOffset, ולהלן האפיון של הפקד:
- פקד זה יוכל לקבל איזור זמן (כ - int), ו - DateTime, ויציג את השעה והתאריך בהתאם לאיזור הזמן.
- אם לא יוגדר איזור זמן, הפקד יתייחס לאיזור הזמן כ - 0.
- אם לא יוגדר DateTime, הפקד יציג את השעה הנוכחית.
- ניתן להחליט האם הפקד יתרנדר כ - div או כ - span.
- ניתן להגדיר את ה - Format שבו יוצג הזמן. (String).
כמובן שעדיין חסרה פונקציונליות לפקד, כמו לדוגמה אם השרת שלנו לא נמצא ב - Time Zone אפס, אבל המטרה היא להסביר איך ליצור פקד ולא איך לגרום לשרת שלכם להציג את השעה הרלוונטית.
נתחיל מיצירת פקד חדש, ניצור Class חדש בשם TimeOffset, ונירש מ - Control.
Properties
Properties או מאפיינים בעברית, הם האפשרויות שאנחנו חושפים למתכנת כשהוא משתמש בפקד שלנו (או ב - Class כלשהו).
לפקד זה יש ארבעה מאפיינים:
- איזור זמן - int
- הזמן שיש להציג - DateTime
- סוג התג שאליו הפקד יתרנדר (אל הסוג אני אגדיר יותר מאוחר)
- Format - String.
ב - .NET 3.0 אפשר ליצור את ה - Properties מבלי להגדיר משתנים פנימיים. אני אציג את זה פה עם משתנים פנימיים למי שעובד עם 2.0 ומטה.
אז נתחיל בהגדרת המאפיינים 1, 2 ו - 4:
public class TimeOffset : Control
{
private int _TimeZone = 0;
private DateTime _TimeToDisplay = DateTime.Now;
private String _Format;
public int TimeZone
{
get { return _TimeZone; }
set { _TimeZone = value; }
}
public DateTime TimeToDisplay
{
get { return _TimeToDisplay; }
set { _TimeToDisplay = value; }
}
public String Format
{
get { return _Format; }
set { _Format = value; }
}
}
המאפיין השלישי צריך לאפשר בחירה בין שתי אפשרויות: div או span. אפשר להשתמש ב - string, ואז לבדוק אותו, אבל הפתרון הזה לא יהיה נוח גם לנו וגם למתכנת שמשתמש בפקד - מכיוון שהוא לא ידע מה האפשרויות שלו. (אלא אם הוא יפנה לדוקומנטציה). הפתרון היותר אלגנטי הוא שימוש ב - enumeration, במקרה כזה בחירה לא נכונה תגרור גם שגיאת קומפילציה ולא רק שגיאת זמן ריצה. נגדיר Enumeration שיכלול את האפשרויות:
public enum RenderingTag
{
div, span
}
ונוסיף את המאפיין השלישי:
private RenderingTag _HtmlTag;
public RenderingTag HtmlTag
{
get { return _HtmlTag; }
set { _HtmlTag = value; }
}
הגדרנו את המאפיינים, נעבור לשלב הבא.
Exceptions
אז למה בעצם אנחנו צריכים Exceptions? מה רע שהפקד שלנו לא יזרוק שגיאות?
בכדי שהפקד שלנו יעבוד בצורה טובה, (במקרה הזה מדובר בפקד פשוט) יש כמה כללים שצריך לעמוד בהם - כמו לדוגמה שה - Time Zone יהיה ואלידי.
הערך של Time Zone צריך להיות בין מינוס 12 ל - 14 (לידע כללי ישראל נמצאת באיזור זמן +2), לכן ב - set של ה - TimeZone נבדוק כי הערך הוא ואלידי, אחרת נזרוק חריגה:
public int TimeZone
{
get { return _TimeZone; }
set
{
if (value > 14 || value < -12)
throw new ArgumentOutOfRangeException("TimeZone",
"The TimeZone must be between -12 and (+)14.");
_TimeZone = value;
}
}
ועכשיו נעבור למתודה Render:
1: protected override void Render(HtmlTextWriter writer)
2: {
3: writer.RenderBeginTag(_HtmlTag.ToString());
4:
5: DateTime DisplayDate = _TimeToDisplay.AddHours(_TimeZone);
6: String DisplayDateString;
7: if (_Format == String.Empty)
8: DisplayDateString = DisplayDate.ToString();
9: else
10: DisplayDateString = DisplayDate.ToString(_Format);
11:
12: writer.Write(DisplayDateString);
13:
14: writer.RenderEndTag();
15: }
להלן הסבר:
בשורה השלישית אנחנו משתמשים במתודה RenderBeginTag של ה - HtmlTextWriter. המתודה הזו מקבלת String או Enum שמגדיר את התג, במקרה שלנו זה div או span כפי שנקבע ע"י המאפיין RenderingTag.
בשורות 5 - 10, אנחנו מוסיפים את ה - Offset לשעה שאנחנו רוצים להציג, ויוצרים את המחרוזת ש"תודפס" באמצעות ה - Format (אם אותחל).
בשורה 12 המתודה Write פשוט תדפיס את המחרוזת שהיא מקבלת.
ובשורה האחרונה המתודה RenderEndTag שלא מקבלת פרמטרים - תסגור את התג האחרון שנפתח.
סיום
מטרת הפוסט הזה הייתה להסביר בפשטות כיצד להשתמש ב - Properties וב - Exceptions. בפוסט הבא בסדרה נדבר על ירושה והרחבה של פקדים קיימים.
מקווה שהחכמתם, ואשמח לתגובות, הערות, הארות והצעות לגבי סדרת הפוסטים הזו.