DCSIMG
Question from Tapuz .Net forum: Nested DataBound Controls - Justin myJustin = new Justin( Expriences.Current );

Question from Tapuz .Net forum: Nested DataBound Controls

שאלה:

יש לנו GridView שנטען מ-DataTable כלשהו ובתוכו יש TemplateField עם DropDownList.

הרשימה של ה- DropDownList   אמורה להתמלא מ Datatable אחר.

איך אני טוען את ה DropDownList  לרשימה נפרדת משלו ?

 

תשובה:

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

נבין קודם את הבעיה ואז נתמקד בפתרון.
נתחיל בליצור דף ASP.Net חדש.

image

לדף נוסיף GridView.

image

ב-GridView שלנו נרצה להציג תמונות של בקבוקי וויסקי, השם שלהם ונאפשר למשתמש לבחור איפה נחזיק את הבקבוק וויסקי שלנו.

נתחיל בליצור מחלקה שתייצג את הבקבוקי וויסקי שלנו. ניצור קובץ חדש בשם WhiskeyBottle.cs.
(יש כמובן לציין שבדוגמה בעולם האמיתי, היינו יוצרים את המחלקה ב-Class Library מחוץ לפרוייקט ה-Web שלנו)

image

קיבלנו את הקובץ הבא:

image

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

    public class WhiskeyBottle

    {

        public WhiskeyBottle(string Name, string PictureUrl, StorageLocation Storage)

        {

            this.Name = Name;

            this.PictureUrl = PictureUrl;

            this.Storage = Storage;

        }

 

        private string _name = string.Empty;

        public string Name

        {

            get { return _name; }

            set { _name = value; }

        }

 

 

        private string _pictureUrl = string.Empty;

        public string PictureUrl

        {

            get { return _pictureUrl; }

            set { _pictureUrl = value; }

        }

 

        private StorageLocation _storage = new StorageLocation();

        public StorageLocation Storage

        {

            get { return _storage; }

            set { _storage = value; }

        }

    }

אין פה הרבה - שלושה מאפיינים (גם באנגלית: Properties) וקונסטרקטור.
ניצור גם קובץ SotrageLocation.cs שיחזיק את מחלקת ה-StorageLocation.

    public class StorageLocation

    {

        public StorageLocation()

        {

        }

 

        public StorageLocation(string Name)

        {

            this.Name = Name;

        }

 

        private string _name = string.Empty;

        public string Name

        {

            get { return _name; }

            set { _name = value; }

        }

 

        public override string ToString()

        {

            return Name;

        }

    }

גם פה אין הרבה, מאפיין אחד, קונסטרקטורים ודרסנו את ToString שנצטרך אותו בהמשך.

 

נבנה ב-Code-Behind של הדף שלנו קצת קוד שייצר לנו נתונים לדוגמה (אשר לכאורה מגיעים מהמסד נתונים).

        public List<StorageLocation> GetStorageLocations()

        {

            List<StorageLocation> ReturnValues = new List<StorageLocation>();

 

            ReturnValues.Add(new StorageLocation("Bar"));

            ReturnValues.Add(new StorageLocation("Closet"));

            ReturnValues.Add(new StorageLocation("On the top shelf"));

            ReturnValues.Add(new StorageLocation("On the low shelf"));

 

            return ReturnValues;

        }

בנינו רשימה של StorageLocation וזאתי תהיה ה-DataSource ל-DropDownList שלנו.

        public List<WhiskeyBottle> GetWhiskeyBottle()

        {

            List<WhiskeyBottle> ReturnValues = new List<WhiskeyBottle>();

 

            ReturnValues.Add(new WhiskeyBottle("Red Label", "~/bottles/RedLabel.jpg", GetStorageLocations()[0]));

            ReturnValues.Add(new WhiskeyBottle("Black Label", "~/bottles/BlackLabel.jpg", GetStorageLocations()[1]));

            ReturnValues.Add(new WhiskeyBottle("Green Label", "~/bottles/GreenLabel.jpg", GetStorageLocations()[1]));

            ReturnValues.Add(new WhiskeyBottle("Gold Label", "~/bottles/GoldLabel.jpg", GetStorageLocations()[2]));

            ReturnValues.Add(new WhiskeyBottle("Blue Label", "~/bottles/BlueLabel.jpg",GetStorageLocations()[3] ));

 

            return ReturnValues;

        }

כאן בנינו רשימה של בקבוקי וויסקי.

 

ניגש בחזרה ל-GridView שלנו ונרצה להוסיף טור טקסטואלי אחד לשם, טור טקסטואלי (ביינתים) למקום אחסון וטור תמונה לבקבוק הוויסקי.

image

נוסיף את שם הבקבוק.

image

את המיקום שלו.

image

ואת התמונה שלו.

image

וזה הקוד ASP.Net שקיבלנו עד כה.

        <asp:GridView ID="grdBottles" runat="server" AutoGenerateColumns="False">

            <Columns>

                <asp:BoundField DataField="Name" HeaderText="Bottle Name"

                    SortExpression="Name" />

                <asp:BoundField DataField="Storage" HeaderText="Location"

                    SortExpression="Storage" />

                <asp:ImageField DataImageUrlField="PictureURL" DataImageUrlFormatString="{0}"

                    HeaderText="Picture">

                </asp:ImageField>

            </Columns>

        </asp:GridView>

(שימו לב בבקשה שהוספתי AutoGenerateColumns=False)

 

נוסיף שתי שורות קוד אחרונות ונריץ את הדוגמה.
יש לנו מקור מידע, יש לנו טבלה, עכשיו רק צריך לחבר ביניהם.

        protected void Page_Load(object sender, EventArgs e)

        {

            grdBottles.DataSource = GetWhiskeyBottle();

            grdBottles.DataBind();

        }

(זוכרים GetWhiskeyBottle מחזיר רשימת בקבוקי וויסקי ואנחנו כתבנו אותה)

 

כאשר נריץ נראה את הדף הבא.

image

 

 

עכשיו נגיע סוף-סוף לבעיה - איך עושים DataBinding ל-DropDownList בתוך GridView.
במקום ה-BoundField שמציג טקסט נרצה להוסיף DropDownList עם רשימת ערכים של StorageLocation.

                <asp:BoundField DataField="Storage" HeaderText="Location"

                    SortExpression="Storage" />

יהפוך ל:

                <asp:TemplateField HeaderText="Location" >

                    <ItemTemplate>

                        <asp:DropDownList ID="ddlLocations" runat="server"

                            DataSource=<%# GetStorageLocations() %>

                            DataTextField="Name" />

                    </ItemTemplate>

                </asp:TemplateField>

 

בואו נראה את זה בהרצה.

image

אז מה עשינו כאן? השתמשנו ב-Late Data Bound Expression ברמת הדף כדי להכניס נתונים לתוך ה-DropDownList.

אבל אפשר לראות משהו מעבר לזה, הנתון שכרגע נבחר ב-DropDownList הוא לא הנתון ברמת המחלקה.
אז נקבע שני מאפיינים ל-DropDownList:
1. לקחת את ה-Value של כל פריט ממהמאפיין Name.
2. לקבוע SelectedValue כ-WhiskeyBottle.Storage.Name.

נשתמש ב-Eval שקשור ל-DataBinding של ההורה כדי להשיג את סעיף 2.

כרגע יש לנו את הקוד הבא ל-DropDownList.

                        <asp:DropDownList ID="ddlLocations" runat="server"

                            DataSource=<%# GetStorageLocations() %>

                            DataTextField="Name" />

והוא יהפוך ל:

    <asp:DropDownList ID="ddlLocations" runat="server"

                            DataSource=<%# GetStorageLocations() %>

                            DataTextField="Name"

                            DataValueField="Name"

                            SelectedValue=<%# Eval("Storage.Name") %>/>

 

נראה איך זה נראה בתצוגה.

image

 

בואו נעשה סדר בבלאגן איך עשינו את זה.

בשלב א' הוספנו GridView ואמרנו שהיא משתמשת ב-DataSource ברמת הדף שנקבע ב-Code Behind.

image

בשלב ב' הוספנו DropDownList שיש לה DataSource ברמת הדף ונקבע בתוך הדף ASP.Net עצמו.

image

בשלב ג' דאגנו שה-DropDownList שלנו תביט על הערך שה-GridView כרגע קבע ל-DataBinding על השורה.
זאת באמצעות ביטוי ה-Eval שקשור לקונטקסט הנוכחי שעובר DataBinding.

image

שימו לב ש-Eval הלך לרמת הקונסטקסט הנוכחי, וביטוי Data Bound אחר הלך ישר לרמת הדף להוציא נתונים.

 

נעשה צעד אחד נוסף ואחרון ונעבור מ-String Based Reference למאפיין ל-Strongly Typed Reference.

                        <asp:DropDownList ID="ddlLocations" runat="server"

                            DataSource=<%# GetStorageLocations() %>

                            DataTextField="Name"

                            DataValueField="Name"

                            SelectedValue=<%# Eval("Storage.Name") %>/>

יהפוך ל:

 <asp:DropDownList ID="DropDownList1" runat="server"

                            DataSource=<%# GetStorageLocations() %>

                            DataTextField="Name"

                            DataValueField="Name"

                            SelectedValue=<%# ((WebTesting_VS2008.WhiskeyBottle)Container.DataItem).Storage.Name %>/>

וזאת כדי שנקבל Intellisense בכתיבת הביטוי ושגיאות קומפילציה למקרה שהמאפיין לא קיים.
(Eval סה"כ ניגש ל-Container.DataItem ומבצע Reflection עליו לפי מחרוזת, אז אנחנו פשוט ישר ניגשנו למאפיין)

 

עוד על Late Data Bound Expressions ניתן לקרוא במאמר שלי משנת 2005:

Late Bound Data Expressions - הכוח שמאחורי הרעיון

 

את הקוד שעבדנו עליו ניתן להוריד - כאן.

 

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

Published Thursday, January 24, 2008 12:59 PM by Justin-Josef Angel [MVP]

Comments

No Comments