קה פרובלמה מואי צ'יקיטה?
בקשר לבעיה השנייה, לא ברור בדיוק מה הבעיה (איזה פקדים לא יזוהו?). קוד מינימלי ורלוונטי כמובן הוא מילת המפתח כאן. בגדול, CrossPagePostBack אמור לדעת לזהות את כל הפקדים על הדף הקודם. הבעיה הראשונה היא דווקא בעיה מאוד מעניינת ומאוד נפוצה - עבודה מול MasterPage מתוך הדף (Page) שלנו. בואו נציג דוגמה מאוד פשוטה. יש לי MasterPage שמציג ככותרת את השם של הדף הנוכחי לפי ה-SiteMapProvider שלי. במימוש הכי בסיסי, יש לי MasterPage עם Label וה-Label.Text שלי מציג את האינפורמציה מקובץ sitemap. נביט על קובץ ה-siteMap:
// Web.sitemap <?xml version="1.0" encoding="utf-8" ?> <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" > <siteMapNode url="Content.aspx" title="Hello world!" /> </siteMap>
אני רוצה שבראש כל עמוד באפליקציה שיש לה MasterPage שהוא יציג אוטומטית את ה-Title מהקובץ XML הזה. נו טוב, נזרוק איזה Label בשם lblHeadline בתוך ה-MasterPage:
// MasterPage.master (desginer) <%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:Label ID="lblHeadline" runat="server" Text="Label"></asp:Label><br /> <asp:contentplaceholder id="ContentPlaceHolder1" runat="server"> </asp:contentplaceholder> </div> </form> </body> </html>
יפה, עכשיו ניקח את הקוד המאוד מאוד מסובך שמכניס את הכותרת של הדף לתוך ה-Label:
public partial class MasterPage : System.Web.UI.MasterPage { protected void Page_Load(object sender, EventArgs e) { lblHeadline.Text = SiteMap.CurrentNode.Title; } }
ניצור דף Content Page בשם Content.Aspx (שמוגדר בקובץ ה-sitemap שלנו) שה-MasterPage שלו הוא ה-MasterPage שלנו. וכאשר נריץ את Content.aspx באמת נקבל שמוצג לנו Hello world. כל זה טוב ויפה ומדגים עבודה עם SiteMapProvider שנהדרת ל-Demoים, אבל איך זה בכלל קשור לשאלה שלך? זה לא. בערך כאן לרוב מפסיקים המאמרים. אז בוא ניקח את זה צעד קדימה, יש לנו דף Content2.aspx והוא לא מוצהר ב-SiteMapProvider (כלומר, אין לו אלמנט ב-web.sitemap) וה-MasterPage שלו הוא ה-MasterPage שלנו. אם ננסה להריץ את הקוד שלנו עכשיו נקבל שגיאה ש-SiteMap.CurrentNode הוא בכלל null והרי זה נכון כי לא הגדרנו SiteMapNode לדף הנוכחי החדש שלנו. לשם הדוגמה שלנו נחליט שאנחנו רוצים שהדף הרגיל שלנו (Content2.aspx) יקבע את הכותרת ב-MasterPage. אנחנו רוצים ש-Content2.aspx יוכל לקבוע את מה שיוצג ב-label ב-MasterPage. דבר ראשון, צריך שננסה לקבוע כותרת רק אם היא קיימת ב-SiteMapProvider:
protected void Page_Load(object sender, EventArgs e) { if (SiteMap.CurrentNode != null) lblHeadline.Text = SiteMap.CurrentNode.Title; }
זה היה החלק הפשוט, עכשיו נחשוף מאפיין (גם באנגלית: Property) מתוך ה-MasterPage שיאפשר לשנות את הטקסט של ה-Label:
public string HeadlineText { get { EnsureChildControls(); return lblHeadline.Text; } set { EnsureChildControls(); lblHeadline.Text = value; } }
לא עשינו כאן הרבה, אמרנו "תקבל מחרוזת, תהיה בטוח שבאמת קיים Label ולתוך ה-Label הזה תכניס את הערך שקיבלת, אההה ואתה גם יכול להחזיר את הערך הנוכחי ב-Label". עכשיו בתוך הדף עצמו נרצה לגשת ל-MasterPage שלנו. חשוב לשים כאן שיש שתי מחלקות שהטיפוס שלהן הוא MasterPage: יש לנו את System.Web.UI.MasterPage ויש לנו את המחלקה שיורשת ממנה בשם MasterPage שיושבת בפרוייקט שלנו. ההבדל הוא שהמחלקה שלנו היא היחידה שמכילה את המאפיין הזה וכל דף באשר הוא מכיל הפנייה לטיפוס של הפריימוורק ולא לטיפוס שלנו. אז בתוך הדף שלנו (Content2.aspx) נמיר את ה-MasterPage שלו לטיפוס MasterPage שלנו ואז ניגש למאפיין.
public partial class Content2 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { MasterPage myMasterPage = (MasterPage) this.Master; myMasterPage.HeadlineText = "www.JustinAngel.Net"; } }
ואכן בתור כותרת נקבל www.JustinAngel.Net. ניגשנו ל-MasterPage של הדף הנוכחי, המרנו אותו מהטיפוס של הפריימוורק לטיפוס שלנו וניגשנו למאפיין שהוספנו לו. וזאת התשובה לשאלה שלך - מאפיינים. עכשיו ניקח את זה עוד צעד קדימה. אני לא רוצה בכל מקום שאני צריך לעבוד מול ה-Properties של ה-MasterPage שלי להמיר תמיד ידנית ל-MasterPage מהטיפוס שלנו. אני רוצה ש-this.Master תמיד יוביל ל-MasterPage שלנו. אז נגיד ככה: כל טופס באפליקציה לא יירש ישירות מ-System.Web.UI.Page אלא יירש ממחלקה שלנו שיורשת מ-Page ותיקרא BasePage.
// BasePage.cs public class BasePage : System.Web.UI.Page { public BasePage() { } } // every *.aspx.cs in the app public partial class Content2 : BasePage
עכשיו נגיד לאפליקציה שכל פעם שפונים ל-this.Master אנחנו רוצים את ה-MasterPage שלנו.
public class BasePage : System.Web.UI.Page { public BasePage() { } public new MasterPage Master { get { return (MasterPage) base.Master; } } }
שים לב לזה שהשתמנו במילת המפתח new ששמנו את התיאור של המאפיין. הסיבה היא שרצינו להשתמש במשהו שלא קיים נכון להיום בדוט נט - Convient types. לא נסביר בדיוק מה זה, אבל נסתפק בזה שאין את זה וכפתרון עקרוני אני משתמש ב-new שצריך להחזיר טיפוס ספציפי שיורש מטיפוס שמוגדר יותר למעלה בהיררכיה. ועכשיו נוכל לכתוב ככה:
// content2.aspx.cs public partial class Content2 : BasePage { protected void Page_Load(ob