DCSIMG
Question From Tapuz .Net Forum: ASP.Net 2.0 Themes - What are they, performance hits and Best practices - Justin myJustin = new Justin( Expriences.Current );

Question From Tapuz .Net Forum: ASP.Net 2.0 Themes - What are they, performance hits and Best practices

שאלה:

האם כדאי לעבוד עם Themes ב-ASP.Net 2.0?
מה הנסיבות בהן אתם משמתמשים בהם?
האם הם גורמים לפגיעה בביצועים?

 

תשובה:

יצא לי לעבוד עם themes עוד מהגרסאות היותר מוקדמות של ASP.Net 2.0 ובהחלט מדובר בכלי עבודה מאוד חזק.
למי שלא מכיר Themes ורוצה להשתתף בדיון:
Visual Studio .Net 2005 - מצגת Webcast שלי בנושא Themes


בהחלט לא תהיה איזהשהי פגיעה בביצועים (של שום דבר) היות ומדובר על אסמבליס מקומפלות לכל דבר שסה"כ מכילות מספר תנאים ברמת ה-Adapter של הדף. אם תשים 1024 פקדים בדף שלכל אחד מהם יש פירוט בקובץ skin, לא מהשימוש ב-Themes תקבל איזהשהי פגיעה רלוונטית בביצועים. הנושא עבר אופטימיזציה מאוד חזקה והטמעה ברמות מאוד גבוהות של הפריימוורק.

 
בוא באמת נראה איך עובד כל נושא ה-Themes הזה מאחורי הקלעים. אנחנו יודעים שפר-פקד יתכן וכי נקבל איזהשהו אתחול של ערכים מסויימים פר Theme ונביט על הנושא מהפרספקטיבה הזו.
בתור התחלה, אנחנו יודעים שכל קוד בדוט נט, גרפי או קוד-קוד, בסופו של דבר יתקמפל לקוד MSIL. כנ"ל תקף ל-Themes. כל Theme, בין אם זה בזמן ריצה או באמצעות Precompilation יתקמפל לאסמבלי משלו. למשל, אם תיקח ותבצע aspnet_precompile לאתר מסויים שיש בו Theme תקבל אסמבלי בתוך ספריית ה-bin בשם App_Themes_MyThemDirectoryName.dll. כל כזה Theme יכיל מערך (ציבורי) של מחלקות ControlSkin שמאפשר לקבל פקד ולהחזיר מחרוזת יחודית לטיפוס שלו ול-SkinID שלו, כך שנוכל לבדוק בתוך ControlSkins של ה-PageTheme אם קיים לה הגדרות בתוך ה-Theme הזה.


איך כל התהליך הזה מתחיל לרוץ בפועל? בשלב ה-PreInit של הדף רצות כמה מתודות קשורות שמאתחלות הפניות CSS פנימיות ואת ה-Theme הרלוונטי. אחרי השלב הזה של הPreInit של הדף, מתחיל שלב ה-Init של הפקדים עצמם כך שבאופן רקורסיבי לכל הפקדים בדף בודקים אם יש לדף Theme ואם הפקדים יכולים לקבל Theme ואם כן מעבירים את זה לטיפול ה-Theme שתבדוק אם צריך להכיל את ה-Theme.

// System.Web.UI.Control
        internal virtual void InitRecursive(Control namingContainer)
        {
...
                if (((this.Page != null) && !this.DesignMode) && (this.Page.ContainsTheme && this.EnableTheming))
                {
                    this.ApplySkin(this.Page);
                }
...
        }

נביט גם על המקום בו הפקד מעביר שליטה לדף, שזה בתורו יעביר שליטה ל-Theme: (בתוך הפקד עצמו מסומן דגל שאומר שכבר הכילו עליו Theme כך שלא יכילו עליו בטעות פעמיים Theme)

// System.Web.UI.Control
        private void ApplySkin(System.Web.UI.Page page)
        {
...
            if (!this.flags[0x400] && ThemeableAttribute.IsTypeThemeable(base.GetType()))
            {
                page.ApplyControlSkin(this);
                this.flags.Set(0x400);
            }
        }

// System.Web.UI.Page
        internal void ApplyControlSkin(Control ctrl)
        {
            if (this._theme != null)
            {
                this._theme.ApplyControlSkin(ctrl);
            }
        }

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

// System.Web.UI.PageTheme
internal void ApplyControlSkin(Control control)
{
...
      ControlSkin skin1 = null;
      string text1 = control.SkinID;
      skin1 = (ControlSkin) this.ControlSkins[PageTheme.CreateSkinKey(control.GetType(), text1)];
      if (skin1 != null)
      {
            skin1.ApplySkin(control);
      }
}

כל מה שמתבצע כאן בפועל זה שנבדק בתוך מערך ה-ControlSkins (שנקבע ע"י מחלקות היורשות מ-PageTheme בזמן קומפליציה) ואם יש פירוט לפקד הזה את מכילים עליו את התכונות השונות. אם אכן קיים כזה פקד הוא עובר למתודה ספציפית בתוך האסמבלי של ה-Theme המקומפל. למשל המתודה הבאה שמכוונת צבע רקע, צבע אות וגודל פונט:

// some compiled Theme
private void __BuildControl__control10(TableItemStyle __ctrl)
{
      __ctrl.BackColor = Color.FromArgb(0xef, 230, 0xf7);
      __ctrl.ForeColor = Color.Black;
      __ctrl.HorizontalAlign = HorizontalAlign.Center;
      Unit unit1 = new Unit(0.800000011920929, UnitType.Em);
      FontUnit unit2 = new FontUnit(unit1);
      __ctrl.Font.Size = unit2;
}

אז בעלות של תנאי אחד-שניים (מקס' חמש) אנחנו מקבלים כאן יכולת מאוד חזקה באמת היות ואנחנו עובדים עם אסמבליס מקומפלות. אני מקווה שזה מפריך כל ניסיון להגיד משהו ברמת "Themes זה לא יעיל" או משהו כזה.


App_Themes הוא פתרון לבעיות. דגש, על בעיות. בניגוד למרבית הדברים שהם פתרון לבעיה יחידה ל-App_Themes יכול להיות מגוון שימושים רב עקב העובדה שבפועל שכל תכונה שנוכל לכוון בזמן Design באמצעות ה-ASP.Net HTML Designer נוכל לכוון בתוך ה-Theme.


השימוש הלא נכון והבנאלי, הוא לקבוע שם כל מיני מאפיינים שבאמת היה אפשר לקבוע ברמת ה-CSS.
למשל, צבע הטקסט, עדיף באמת לקבוע ברמת ה-CSS.


אז מה כן שימוש טוב? באמצעות Themes ניתן לקבוע לכל מחלקה מסוג מסויים CssClass משלה. כלומר, ניתן להכיל למשל על כל ה-Labelים בבת-אחת אותה הגדרה של מחלקת CSS. ברור שיש כאן המון יכולת כי אנחנו משלבים בין עבודה נכונה ב-CSS והפריימוורק.


מה עוד שימוש טוב? לקבוע מאפיינים תצגותיים שאי-אפשר לקבוע ב-CSS.
ב-CSS אני לא יכול לקבוע את התמונה שתוצג בתגית <img>, ב-CSS אני לא יכול לקבוע את מידת הרווח שיש בתוך TreeView, ב-CSS אני לא יכול לקבוע את הסידור הטקסטואלי של טקסט בתוך Menu. למרות שיש פתרונות יותר מתקדמים לנושא הזה (סטייל Css Control Adapters) באמת מדובר בצעד הבא, אבל שלא בהכרח תמיד נדרש ומדובר בלמידה של נושא חדש לחלוטין כדי לישם אותו.


עוד שימוש טוב וכאן הכוח האמיתי של Themes הוא בקביעת מאפיינים התנהגותיים ו-Templateים למיניהם.
הכוונה היא שנוכל לקבוע למשל לכל ה-GridViewים שלנו במקום אחד מרוכז איזה טורים נרצה לראות בהם, נוכל לקבוע ל-Login שלנו איך נרצה שהוא יראה ועם אילו שדות, נוכל לקבוע אם פקד בכלל מרונדר או לא. זה הרבה מאוד כוח ובשימוש במדיניות מקיפה מאפשר הקמה ותחזוקה יחסית פשוטה של המון דברים.

קישור:  http://www.tapuz.co.il/tapuzforum/main/Viewmsg.asp?forum=831&msgid=88943999

Published Friday, November 10, 2006 7:42 PM by Justin-Josef Angel [MVP]

Comments

No Comments