שאלה:
מה הדרך הנכונה לבנות אפליקציה אינטרנטית סטייל GMAIL,
שבה כל הניווט והפעולות באתר מתבצע בצורה שקטה ?
תשובה:
האפשרות הפשוטה היא להשתמש ב-Fake AJAX שזה דף שעובד רגיל עם PostBackים רק שיש אפקט צד לקוח שגורם להכל להיראות כאילו הוא AJAX.
Fajax -- the fake alternative to ajax
האפשרות היותר מתוחכמת היא לעבוד עם AJAX אמיתי, ספציפית עם Microsoft AJAX Libary (לשעבר: אטלס).
קיים אלמנט בשם UpdatePanel שהקונספט מאחוריו הוא לאפשר מה שנקרא PartialRendering, שזה רנדור מחדש של כל הפנאל בלי לגרום לרנדור מחדש של כל הדף. אם אתה רוצה "ניווט שקט" "סטייל GMAIL" תוכל להכניס את כל התוכן של האתר לתוך UpdatePanel.
רק שזה דורש שינוי קל במחשבה מאשר תכנות ASP.Net רגיל. בתכנות ASP.Net רגיל היית שם את כל תוכן האתר בתוך ContentTemplate של MasterPage ומצפה להצליח להחליף את ה-Content כרצונך. עקב העובדה שה-MasterPage הוא בפועל User Control של Page לא ניתן להחליף באופן דינמי Pageים, אלא רק MasterPages.
ככה שאתר שנבנה ככה יצטרך להיבנות בצורה שבנינו אתרים לפני MasterPages, עם הרבה User Controls. את כל הדפים באפליקציה כזו תצטרך להמיר ל-User Control שזה בעקרון עניין של שינוי שם הקובץ ל-ASCX, את ה-Page Directive בראש הדף ואת המחלקה ממנו יורשת ה-Partial של ה-Code Behind (וגם יש כלים אוטומטים שעושים את זה).
נביט על זה במטאפורה של טלוויזיה למשל. אנו רוצים שרק המשבצת באמצע תתרנדר מחדש כל פעם שאנחנו מחליפים תחנה אבל כל "המסביב" ישאר זהה.
בשביל זה נכניס כל פעם User Control מה-User Controls שפעם היו הדפים שלנו לתוך ה-ContentTemplate של ה-UpdatePanel שלנו.
אם היינו בונים את זה עם PostBackים קל לראות שהיינו יוצרים משהו סטייל PlaceHolder שצמוד אליו כל פעם פקד אחד בדיוק. היינו יוצרים בצד רשימת כפתורים שדואגת שכל פעם שלוחצים אליה הייתה מחליפה את ה-UserControl שצמוד ל-PlaceHolder בזה שהיא תנקה את הפקד הקיים ממנו ותוסיף את הפקד המתאים (לפי איזה כפתור נלחץ).
עכשיו השאלה היא - אנחנו לא רוצים PostBackים איך עושים את זה בAjax?
דבר ראשון זה להפעיל PartialRendering ברמת ה-ScriptManager בזה שנקבע לו EnablePartialRendering=true.
מה שנקבל מזה זה שכל אירוע שבעבר היה דורש PostBack לשרת בתוך ה-UpdatePanel כעת גורם ל-Partial Rendering של כל התוכן בתוך ה-Update Panel.
נרצה להגביל את האירועים שיוצרים Partial Rendering וריצה לשרת ונקבע ל-UpdatePanel שלנו Mode="Conditional" שזה אומר שצריך לפרט איזה טריגר גורם לרנדור מחדש לקרות. טריגר לרנדור מחדש יכול להיות שינוי של ערך של פקד צד-משתמש (למשל, שינוי הערך של תיבת טקסט) או אירוע צד-משתמש (למשל, לחיצה על כפתור).
הטריק האמיתי כאן זה לגרום לכפתורים מחוץ ל-UpdatePanel לגרום לרנדור מחדש של ה-UpdatePanel.
נוכל להוסיף ל-UpdatePanel שלנו טריגר מסוג ControlEventTrigger שמקשיב לכל הכפתורים שלנו. למעשה מה שיקרה זה שבצד לקוח הוא יקשיב ללחיצה על הכפתורים האלו ויגיד "אם הם נלחצו, תרנדר את ה-UpdatePanel מחדש".
כמו כן, נרצה להעביר איכשהו דרך ה-UpdatePanel את המידע של איזה כפתור נלחץ אחרון ובשביל זה נשמור משתנה HtmlHiddenInput שיהיה נגיש לשינוי צד-לקוח ויקלט בצד-שרת.
בגדול, יש כמה אפשרויות לגרום לכפתור לעדכן UpdatePanel:
1. להוסיף ControlEventTrigger על אירוע הלחיצה של הכפתור בתוך הטריגרים של ה-UpdatePanel. אפשר לרשום את זה כקוד Designer Hard-coded בצורה הבאה:
<Triggers>
<atlas:ControlEventTrigger ControlID="Panel3bButton" EventName="Click" />
</Triggers>
עדיף כמובן לבצע את זה תכנותית כדי שהניווט באתר יהיה יותר גמיש והקישור בין הכפתור לבין הרפרוש של ה-UpdatePanel.
protected void Page_Load(object sender, EventArgs e)
{
Button btn = new Button();
btn.ID = "btnUpper";
btn.Click += new EventHandler(btn_Click);
btn.Text = "To upper";
UpdatePanel2.Controls.Add(btn);
Microsoft.Web.UI.ControlEventTrigger trig = new Microsoft.Web.UI.ControlEventTrigger();
trig.ControlID = "btnUpper";
trig.EventName = "Click";
trig.OnEvent(btn, new EventArgs());
UpdatePanel1.Triggers.Add(trig);
}
// copied from: http://aspspider.org/sevob/asp/atlas/uppnl1.aspx
2. ניתן לרשום כל כפתור וכפתור למתודת ScriptManager.RegisterAsyncPostBackControl ברמת הדף.
myScriptManager.RegisterAsyncPostBackControl(Button1);
3. אם אתה עובד עם פקד כמו TreeView שיש לו אירועים צד-לקוח ללחיצה על Nodeים תרצה לתפוס את האירועים צד-לקוח האלו, ולגרום שם לרפרוש של ה-UpdatePanel (ולמנוע את המשך ביצוע הפניית ה-HTTP בגלל שהלקוח לחץ על הכפתור). בשביל זה תוכל ליצור את פקד ה-UpdatePanel בצד לקוח ולקרוא למתודת Update שלו.
עכשיו השאלות המעניינות לסגנון:
האם חייבים לעבוד עם כפתורים? אפשר גם לעבוד עם HyperLinkים וליצור ControlEventTrigger לאירוע Click שלו.
האם אפשר לממשק את זה ישירות ל-TreeView? בגדול, לא. TreeView מרנדר אוסף של TreeNodes ואלו אינם מכילים פקדים צד-שרת משום סוג, הם מרנדרים HTML ישירות. אם אין לך ניסיון בלשבור בכוח את הפריימוורק (להוציא שתי מחלקות מאוד כבדות החוצה, ולשנות מתודה פנימית מאוד ענפה שהיא המתודה של הרנדור של TreeNode) מומלץ לא לנסות את ההתאמה הזאת. אמור להיות אירוע צד-לקוח בשם TreeView_SelectNode שקורה כל פעם שלוחצים על קישור ב-TreeView. אם תוכל להירשם לאירוע הזה או להשתלט על הרנדור צד-לקוח שלו תוכל לגרום לרנדור מחדש של ה-UpdatePanel ע"י קריאה למתודה צד-לקוח של UpdatePanel בשם Update.
אני ממליץ בחום שתקרא את שני המאמרים הבאים על UpdatePanel ולעבור עליהם בדקדוק ובמיוחד על הדוגמאות.
Server Class Library > UpdatePanel Class
Walkthrough: Using an "Atlas" UpdatePanel
היות והתשובה כאן והמאמרים הנ"ל מתייחסים ל-July CTP צריך להוריד את התיעוד מ-ASP.NET AJAX July CTP Documentation.
קישור: http://www.tapuz.co.il/tapuzforum/main/Viewmsg.asp?forum=831&msgid=87754870