DCSIMG
[Tapuz .Net] ASP.Net 2.0 Wizard Control SideBar Rendering - Justin myJustin = new Justin( Expriences.Current );

[Tapuz .Net] ASP.Net 2.0 Wizard Control SideBar Rendering

שאלה:

האם ניתן להזיז את רשימת הצעדים ב-Wizard כך שתופיע מעל הפקדים (כמו טאבים)?

 

תשובה:

שאלה מצויינת שבאמצעותה נוכל לחפור קצת לתוך מערכת ה-Rendering של ASP.Net 2.0.

בואו נראה מה השלבים שניקח כדי לרדת לשורש הבעיה ולבסוף לפתור אותה:

image

 

ניצור דף ASP.Net חדש שעליו נדגים את הבעיה.

image

נוסיף לטופס שלנו פקד Wizard.

image

וקיבלנו את הפקד Wizard הברירת מחדל:

image

בשביל הדוגמה נעשה כמה שינויים קוסמטיים קטנים.

נגדיל את הפקד.

image

נעשה לו Auto-Format שיהיה יותר וויזאולי ברור מה אנחנו מנסים לעשות.

image

image

נוסיף עוד שני Steps ל-Wizard.

image

image

image

ולבסוף, נוסיף קצת טקסט לכל Wizard Step שלנו.

image

image

כנ"ל נעשה גם לצעד 2 וצעד 4.

 

זהו, הקמנו דוגמה קטנה ל-Wizard של ASP.Net 2.0.

נריץ את הדוגמה.

image

בלחיצה על Next נעבור לשלב הבא.

image

 

עכשיו, השאלה היא איך ניתן להעביר את ה-Sidebar לחלק העליון של פקד ה-Wizard.

אין אפשרות מובנית כזאת.

בואו נביט על ה-HTML שמייצר ה-Wizard שלנו.
אני אשתמש ב-Internet Explorer Developer Toolbar בשביל זה.
גולשי FireFox יכולים להשתמש ב-FireBug.
ואלו מכם שגולשים בדפדפנים אחרים יכולים להשתמש ב-Notepad לעיין ב-HTML.

נבחר ב-Select Element By Click.

image

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

image

image

בחרנו את ה-Wizard שלנו ונוכל לראות את ההיררכיית פקדים שלו ובתוכו.

image

אפשר לראות ש-Wizard1 מתרגם לתגית <table> ב-HTML.

בתוך ה-<table> הראשי יש שורה אחת של תגית <tr> ובתוכו יש שני תאי <td> ובתוך כל אחד מאלו עוד טבלה <table>.

למי מאתנו שמבין באיך מעצבים HTML ומזועזע מהחוסר בשימוש בתגיות <div>ים כאן, אני מסכים. אם כי, שמפתחים פריימוורק צריך לרוב לבחור באפשרות שיותר קל לתמוך ולקסטם.

 

צריך לדאוג שה-Wizard ירנדר בטבלה שלו שתי שורות עם תא אחד בכל אחד מהם, ולא שורה אחת עם שני תאים.

נפתח את Reflector על System.Web.UI.WebControls.Wizard.

image

 

הדבר הראשון שתופס לנו את העין צריך להיות הירושה מ-CompositeControl.
CompositeControl היא סוג ספציפי של Custom Control ב-ASP.Net.
הרעיון הוא ש-Custom Control הוא פקד "יחיד" ו-Composite Control הוא איחוד בין מספר פקדים.

מהיכרות עם Composite Controls אנחנו יודעים לפתוח ישר את מתודת ה-CreateChildControls שבתוכה מפרטים תמיד איזה פקדים מתווספים להיררכיה.

image

אפשר לראות כאן קריאה למתודה בשם CreateControlHierachy.

אם נביט לתוכה נראה את הקוד המבהיל הבא.

image

 

מסכימים איתי זה לא קוד סימפטי ויחסית קשה לעקוב אחריו?

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

אני הבנתי מהקוד הזה דבר אחד ל-this.Controls מוסיפים טבלה ראשית כלשהי.
אז לפי דעתי, אם נירש (גם באנגלית: Inherit) את Wizard ונדרוס את המתודה הזאת נוכל לשנות את אוסף הפקדים הפנימי.

 

נתחיל בלפתוח פרוייקט חדש מסוג Web Control Library.

image

image

שימו לב שב-Visual Studio 2008 שם הפרוייקט השתנה מ-ASP.Net Web Control Library ל-ASP.Net Server Control.

 

נוסיף פקד myWizard שיורש מ-Wizard.

image

image

ונשנה את הקוד ברירת מחדל ככה שיכיל את הירושה הריקה מ-Wizard.

using System.Web.UI.WebControls;

 

namespace WebControlLibrary_VS2008

{

    public class myWizard : Wizard

    {

 

    }

}

רק נדאג להוסיף את ה-Reference בין הפרוייקט Web שלנו ל-Web Control Library ונתקדם עם הפקד.

image

image

 

הגענו עכשיו לכתיבת הפקד שלנו.

נדרוס את המתודה CreateControlHierachy וכרגע גם הוספתי אליו BreakPoint כדי שעוד מעט נתחקר את this.Controls.

image

 

עכשיו נשנה את הקוד ASP.Net הקיים שלנו שיעבוד עם myWizard ולא ה-Wizard הברירת מחדל.

בקובץ ה-web.config שלנו נוסיף הרשמה ל-Web Control Library שלנו.

        <pages>

            <controls>

                <add assembly="WebControlLibrary_VS2008" namespace="WebControlLibrary_VS2008" tagPrefix="my" />

            </controls>

        </pages>

ובמקום להשתמש ב-<asp:Wizard> נשתמש בתגית ה-<my:myWizard>.

<asp:Wizard ID="Wizard1" runat="server">
...
</asp:Wizard>

 
 

<my:myWizard ID="Wizard1" runat="server">
...
</my:myWizard>

 

עכשיו שנריץ את האפליקציה Visual Studio עצר בשורה שביקשנו שיעצור.

image

נפתח את חלון ה-Quick Watch באמצעות קיצור המקלדת Ctrl + Alt + Q ונבקש ממנו לבדוק את this.Controls.

image

נחפור קצת בהיררכית הפקדים.

image

image

אפשר לראות שיש לנו WizardControlCollection שמכיל WizardChildTable שמכיל RowControlCollection שמכיל TableRow וזה מכיל בתורו AccessiableTableCell שהוא ה-SideBar ו-TableCell נוסף שזה ה-Wizard עצמו.

 

דבר ראשון, ניצור פרמטרים בפונקציה הזו שמפנים לכיוון ה-RowControlCollection ושני התאים.

        protected override void CreateControlHierarchy()

        {

            base.CreateControlHierarchy();

 

            Control wizardRows = this.Controls[0];

            TableCell sideBar = (TableCell) wizardRows.Controls[0].Controls[0];

            TableCell wizard = (TableCell) wizardRows.Controls[0].Controls[1];

        }

דבר שני שנרצה לעשות זה להוריד את ה-sideBar מהשורה שהוא כרגע נמצא בה.

        protected override void CreateControlHierarchy()

        {

            base.CreateControlHierarchy();

 

            Control wizardRows = this.Controls[0];

            TableCell sideBar = (TableCell) wizardRows.Controls[0].Controls[0];

            TableCell wizard = (TableCell) wizardRows.Controls[0].Controls[1];

 

            sideBar.Parent.Controls.Remove(sideBar);

        }

ולבסוף, ניצור TableRow חדש שלתוכו נכניס את ה-TableRow ונשים את ה-TableRow כשורה הראשונה בטבלת השורות.

        protected override void CreateControlHierarchy()

        {

            base.CreateControlHierarchy();

 

            Control wizardRows = this.Controls[0];

            TableCell sideBar = (TableCell) wizardRows.Controls[0].Controls[0];

            TableCell wizard = (TableCell) wizardRows.Controls[0].Controls[1];

 

            sideBar.Parent.Controls.Remove(sideBar);

 

            TableRow sideBarRow = new TableRow();

            sideBar.Height = new Unit(10);

            sideBarRow.Controls.Add(sideBar);

            wizardRows.Controls.AddAt(0, sideBarRow);

        }

 

אם נריץ את הדוגמה כעת, זה יראה כך:

image

ואם נלחץ על Next נקבל:

image

 

עוד צעד שהייתי רוצה לעשות זה לתחום את השינוי שביצענו להעברת ה-SideBar להיות TopBar זה לשים מאפיין על הפקד ששואל אם באמת צריך לעשות את זה.

זאת גם הזדמנות טובה להדגים Encapsulate Field Refactoring ו-Extract Method Refoactoring.

 

נוסיף שדה בוליאני בשם showToBar_ ונאתחל אותו כברירת מחדל ל-false.

    public class myWizard : Wizard

    {

        protected override void CreateControlHierarchy()

        {

            ...

        }

 

        private bool _showTopBar = false

    }

בתוך Visual Studio 2008\2005 נלחץ Ctrl + R, Ctrl + E או כפתור ימני על שם השדה ונבחר Refactor --> Encapsulate Field.

image

נלחץ פעמיים על מקש האנטר ונקבל את המאפיין מסביב לשדה.

    public class myWizard : Wizard

    {

        protected override void CreateControlHierarchy()

        {

            ...

        }

 

        private bool _showTopBar = false;

 

        public bool ShowTopBar

        {

            get { return _showTopBar; }

            set { _showTopBar = value; }

        } 

    }

נוסיף גם קצת מאפיינים ל-Design Time כדי שלמאפיין יהיה ערך ברירת מחדל ויופיע במקום הנכון ב-Properties של הפקד.

        private bool _showTopBar = false;

        [Category("Behavior"), DefaultValue(false)]

        public bool ShowTopBar

        {

            get { return _showTopBar; }

            set { _showTopBar = value; }

        } 

עכשיו נוציא את כל הקוד שלנו למתודה יעודית. נסמן את כל הקוד בתוך CreateControlHierachy.

image

נלחץ Ctrl + R, Ctrl + M או נלחץ כפתור ימני, אז Refactor ובסוף Extract Method.
נקבע שם חדש למתודה שתכיל את כל הקוד שסימנו.

image

ככה נראה הקוד של המחלקה כעת:

    public class myWizard : Wizard

    {

        protected override void CreateControlHierarchy()

        {

            base.CreateControlHierarchy();

 

            moveSideBarToTopBar();

        }

 

        private void moveSideBarToTopBar()

        {

            Control wizardRows = this.Controls[0];

            TableCell sideBar = (TableCell)wizardRows.Controls[0].Controls[0];

            TableCell wizard = (TableCell)wizardRows.Controls[0].Controls[1];

 

            sideBar.Parent.Controls.Remove(sideBar);

 

            TableRow sideBarRow = new TableRow();

            sideBar.Height = new Unit(10);

            sideBarRow.Controls.Add(sideBar);

            wizardRows.Controls.AddAt(0, sideBarRow);

        }

 

        private bool _showTopBar = false;

        [Category("Behavior"), DefaultValue(false)]

        public bool ShowTopBar

        {

            get { return _showTopBar; }

            set { _showTopBar = value; }

        } 

    }

נוסיף תנאי if על המאפיין הבוליאני שלנו לפני שמבצעים את המתודה.

using System.ComponentModel;

using System.Web.UI;

using System.Web.UI.WebControls;

 

namespace WebControlLibrary_VS2008

{

    public class myWizard : Wizard

    {

        protected override void CreateControlHierarchy()

        {

            base.CreateControlHierarchy();

 

            if (ShowTopBar)

                moveSideBarToTopBar();

        }

 

        private void moveSideBarToTopBar()

        {

            Control wizardRows = this.Controls[0];

            TableCell sideBar = (TableCell)wizardRows.Controls[0].Controls[0];

            TableCell wizard = (TableCell)wizardRows.Controls[0].Controls[1];

 

            sideBar.Parent.Controls.Remove(sideBar);

 

            TableRow sideBarRow = new TableRow();

            sideBar.Height = new Unit(10);

            sideBarRow.Controls.Add(sideBar);

            wizardRows.Controls.AddAt(0, sideBarRow);

        }

 

        private bool _showTopBar = false;

        [Category("Behavior"), DefaultValue(false)]

        public bool ShowTopBar

        {

            get { return _showTopBar; }

            set { _showTopBar = value; }

        } 

    }

}

נחזור לפרוייקט ASP.Net שלנו ושנה את ShowTopBar ל-true.

image

 

אכן עכשיו שקבענו את ShowTopBar=True נקבל את ה-SIdeBar מעל ה-Wizard.

image

 

נסכם את הגישה שלנו לבעיה והצעדים שלקחנו.

image

 

ניתן להוריד את הקוד שעבדנו עליו מכאן - http://www.JustinAngel.Net/files/Example-Wizard-TopBar.zip.

 

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

Published Tuesday, March 11, 2008 12:18 PM by Justin-Josef Angel [MVP]

Comments

No Comments