User Control

בטיטi

New member
../images/Emo41.gif User Control

יש לי User Control שמכיל DropDownList, ויש לי דף שמכיל אותו. 1. שמתי לב שה Page_Load של המסך רץ לפני ה Page_Load של הקונטרול, לכן אני לא יכול לאתחל את הקונטרול ב Page_Load של המסך, אלא רק בשלב מאוחר יותר, למשל OnPreRender של המסך.
האם הבנתי נכון, וכך עושים זאת ? 2. סעיף 1 עבד בהצלחה, כעת הוספתי למסך כפתור, שמבצע פוסטבק, במתודת ה Click של הכפתור (בשרת), אני ניגש ל SelectedValue של ה DropDownList בקונטרול, אך תמיד אני מקבל את הערך הראשון ברשימה, ולא באמת את הערך שהגולש בחר.
מדוע ? 3. כאשר אני חושף Property מתוך הקונטרול (listTitle בדוגמא) האם אני יכול לקבוע עבורו ערך גם מתוך ה aspx, ולא רק מתוך ה Code Behind ? למשל : myControls:myDDL id="aaaa" runat=server listTitle=yesyesyes
 

dino_din

New member
סעיף 2 זו כנראה בעייה של

מי רץ קודם. אני רק משער כמובן כי לא ראיתי את כל הקוד. אחרי שלחצת על כפתור, הדף נטען שוב ואחריו ה UC. בשלב זה, אתה בטח טוען שוב את הערכים ל LISTBOX ולכן הבחירה האחרונה לא נשמרת לך. רק אחרי טעינת העמוד וה LISTBOX מופעל אירוע הכפתור ואז ה LISTBOX כבר היתאפס (כי טענת לתוכו ערכים חדשים). יכול להיות שצריך לשמור את האינדקס הנבחר של ה LISTBOX לפני שאתה מאתחל אותה שוב ובלחיצת כפתור לבדוק בתוך אירוע הלחיצה מה ערך ה INDEX ששמרת קודם (כמובן שבפעם הראשונה לבדוק שיש ערכים לפני שאתה שומר את ה INDEX כי אז הוא -1). בהצלחה.
 

Justin Angel

New member
קה פרובלמה מואי צ'יקיטה?

1. הבנת נכון את רצף האירועים. Page מבצע ראשון את כל האירועים שלו, ואז כל מיני סוגי דפים אחרים שקשורים אליו (UserControls ו-MasterPages) מריצים את האירועים שלהם. לא ברור לי מה הכוונה ב"לאתחל את הקונטרול", ה-UserControl נוצר כמו כל פקד אחר שהוספת באמצעות ה-Designer לפני ה-Page_load ולכן כבר מאותחל. אם למשל אתה מתכוון שאתה לא יכול לגשת לפקדים הפנימיים של UserControl בשלב ה-Page_load של הדף שמכיל אותו, בזה אתה צודק. אתה אמור לקבל על זה שגיאה כי באמת הפקדים בפנים לא מאותחלים. במצבים מאוד פשוטים כאלו, אתה לא תקבל את השגיאה הזו כי איפהשהו מתבצעת אופטימיזציה שקולטת "איזה טיפש התוכניתן, הוא מנסה לגשת לפקד שלא קיים, אני אצור את הפקדים בפנים קודם". האופטימזיציה הזאת מושלמת להדגמות מול קהל ומפסיקה לעבוד ברגע שהדף מספיק מסובך (ע"ע Real world). כ-כלל אצבע, מה שעושים במצבים כאלו שרוצים לגשת לפקדים של Custom Control או User Control שיתכן שקיימים ויתכן שאינם קיימים הם לדאוג שהפקדים קיימים. בתוך כל Property שאתה חושף לפני שאתה ניגש לפקדים עצמם תצטרך לקרוא למתודה EnsureControlsCreated. זאת מתודה שנמצאת בשימוש נרחב בכל מקום שבו כותבים פקדים באמת כדי לוודא שקיימים פקדים לפני שניגשים אליהם מתוך Properties למיניהן שאינן קשורות בישירין לסדר האירועים הדיפולטי של הדף. יש דוגמה לזה בשאלה על MasterPages של אוהד מלפני שבוע. 2. אי-טעינת מידע ViewState או PostBack נגרמת ב-99% מהמקרים ע"י דבר אחד: ה-ID של הפקד שאמור לקלוט את הערכים אינו קבוע ומשתנה בין PostBackים. ViewState מספק בסופו של דבר זוגות של "מפתחות-ערכים" כאשר המפתח הוא ה-ID של הפקד והערך הוא הערך הנבחר הקודם שלו. אחרי PostBack אנו מקבלים מרשימת Request.Form רשימת IDים של פקדים ואת הערכים החדשים שלהם שנבחרו. הכל מבוסס על זה ש-ID הוא קבוע ולא ישתנה. אם אחד מהשניים לא נטען, תביט על Request.Form אחרי PostBack ותראה את ה-ID של הפקד שהוא מנסה לשלוח לו ערכים. ה-ID הוא למעשה הרכבה של ההיררכיה המלאה של NamingContainers שבתוכו יושב הפקד. אחד מהאלמנטים שם יהיה עם שם כמו ctl001 וזה הפקד בעל השם הבלתי קבוע. הפתרון הוא לקבוע לכל הפקדים בהירככיה הזו ID קבוע ברמת הקוד. 3. כל מאפיין שמוסיפים ל-Controls זמין לשינוי דרך ה-Property Grid של ASP.Net או דרך קוד ה-ASP.Net עצמו. גם אם מדובר באלמנט שהוא מורכב מאלמנטים אחרים (למשל אלמנט Style שמורכב תמיד ממספר אלמנטים וניגשים אליו דרך היררכיה של Style-MyStyleMember) מתוך קוד ה-ASP.Net.
 

בטיטi

New member
תודה, תגובה :

1. הבנתי, לגבי ה EnsureControlsCreated : אם אני מבין נכון, זו רק בדיקה כדי למנוע תעופה, שום דבר מעבר, נכון ? 2. מדוע שה ID של הקונטרול ישתנה במקרה הפשוט שתארתי ? 3. כלומר, זה אפשרי Built In ? האם שם המאפיין אמור גם להופיע אוטומטית ב Intellisense ? (כמו למשל כשלוחצים על מקש הרווח, ואפשר לבחור את המאפיין runtat מתוך הרשימה הנגללת) Thanks
 

Justin Angel

New member
../images/Emo26.gif

1. זה בודק אם לא נוצרו פקדים בפקד הנוכחי, ואם לא אז הוא יוצר אותם. ככה שאתה יודע שאחרי שהרצת אותו בטוח וקיימים הפקדים מולם אתה עובד. 2. לרוב ה-ID הפקדים ישתנו כדי למנוע "התנגשויות" בין הפקדים הקודמים. הבעיה היא ש-ASP.Net מאוד חלש מהבחינה הזו של יצור IDים דינמיים וכל פשרה בחוקיות של יצירת ID דינמי יכולה לגרום להמון דברים להפסיק לעבוד. 3. כן. יש תמיכה אומטית בהוספת Custom Everything בתוך כל מקום שאפשר לדמיין ב-Visual Studio ובפרט בכל מקום שתומך ב-Intellisense.
 

Justin Angel

New member
והקוד של EnsureControlsCreated

protected virtual void EnsureChildControls() { if (!this.ChildControlsCreated && !this.flags[0x100]) { this.flags.Set(0x100); try { this.ResolveAdapter(); if (this._adapter != null) { this._adapter.CreateChildControls(); } else { this.CreateChildControls(); } this.ChildControlsCreated = true; } finally { this.flags.Clear(0x100); } } }​
flags[0x100] למקרה שמעניין אותך זה דגל ברמת הפקד שנועלים אותו שמתחילה יצירת הפקדים המקוננים שלו כדי שלא יווצר מצב ששני CreateChildControls רצים בו זמנית.
 

בטיטi

New member
1. אבל זו לא התערבות גסה

במחזור החיים של פקד/דף ? אתה הרי מכריח את הפקד להווצר לפני הזמן המתוכנן שלו, לא ?
 

Justin Angel

New member
../images/Emo26.gif

לא. זמן יצירת הפקדים היא לא חלק ממחזור החיים של דף, היא משהו שהכרח שיש דברים שקורים קודם ויש דברים שקורים אחר-כך. זוהי שיטת העבודה המקובלת והמומלץ ע"י מיקרוסופט. מחזור החיים של דף מוגדר כחלק מרצף אירועים ספציפי מאוד: (מתוך ProcessRequestMain בתוך הפריימוורק)
if (this.MaintainScrollPositionOnPostBack) { this.LoadScrollPosition(); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin PreInit"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_INIT_ENTER, this._context.WorkerRequest); } this.PerformPreInit(); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_INIT_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End PreInit"); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin Init"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_INIT_ENTER, this._context.WorkerRequest); } this.InitRecursive(null); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_INIT_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End Init"); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin InitComplete"); } this.OnInitComplete(EventArgs.Empty); if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End InitComplete"); } if (this.IsPostBack) { if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin LoadState"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_VIEWSTATE_ENTER, this._context.WorkerRequest); } this.LoadAllState(); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_VIEWSTATE_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End LoadState"); this.Trace.Write("aspx.page", "Begin ProcessPostData"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_POSTDATA_ENTER, this._context.WorkerRequest); } this.ProcessPostData(this._requestValueCollection, true); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_POSTDATA_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End ProcessPostData"); } } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin PreLoad"); } this.OnPreLoad(EventArgs.Empty); if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End PreLoad"); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin Load"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_ENTER, this._context.WorkerRequest); } this.LoadRecursive(); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End Load"); } if (this.IsPostBack) { if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin ProcessPostData Second Try"); } this.ProcessPostData(this._leftoverPostData, false); if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End ProcessPostData Second Try"); this.Trace.Write("aspx.page", "Begin Raise ChangedEvents"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_POST_DATA_CHANGED_ENTER, this._context.WorkerRequest); } this.RaiseChangedEvents(); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_POST_DATA_CHANGED_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End Raise ChangedEvents"); this.Trace.Write("aspx.page", "Begin Raise PostBackEvent"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RAISE_POSTBACK_ENTER, this._context.WorkerRequest); } // next page in next message​
 

Justin Angel

New member
../images/Emo26.gif המשך

this.RaisePostBackEvent(this._requestValueCollection); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RAISE_POSTBACK_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End Raise PostBackEvent"); } } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin LoadComplete"); } this.OnLoadComplete(EventArgs.Empty); if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End LoadComplete"); } if (this.IsPostBack && this.IsCallback) { this.PrepareCallback(text2); } else if (!this.IsCrossPagePostBack) { if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin PreRender"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_RENDER_ENTER, this._context.WorkerRequest); } this.PreRenderRecursiveInternal(); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_RENDER_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End PreRender"); } } } if ((this._asyncInfo == null) || this._asyncInfo.CallerIsBlocking) { this.ExecuteRegisteredAsyncTasks(); } if (includeStagesAfterAsyncPoint) { if (this.IsCallback) { this.RenderCallback(); } else if (!this.IsCrossPagePostBack) { if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "Begin PreRenderComplete"); } this.PerformPreRenderComplete(); if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End PreRenderComplete"); } if (context1.TraceIsEnabled) { this.BuildPageProfileTree(this.EnableViewState); this.Trace.Write("aspx.page", "Begin SaveState"); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_SAVE_VIEWSTATE_ENTER, this._context.WorkerRequest); } this.SaveAllState(); if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_SAVE_VIEWSTATE_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End SaveState"); this.Trace.Write("aspx.page", "Begin SaveStateComplete"); } this.OnSaveStateComplete(EventArgs.Empty); if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End SaveStateComplete"); this.Trace.Write("aspx.page", "Begin Render"); } if (this.MaintainScrollPositionOnPostBack && (this._form == null)) { throw new HttpException(System.Web.SR.GetString("MaintainScrollPositionSetWithNoServerForm")); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RENDER_ENTER, this._context.WorkerRequest); } if (text1 != null) { this.ExportWebPart(text1); } else { this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output)); } if (EtwTrace.IsTraceEnabled(5, 4)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RENDER_LEAVE, this._context.WorkerRequest); } if (context1.TraceIsEnabled) { this.Trace.Write("aspx.page", "End Render"); } this.CheckRemainingAsyncTasks(); }​
 

idv

New member
לגבי 2

בהנחה שאתה טוען את הנתונים ל DDL במהלך ה page_load שרץ לפני הclick של הכפתור תוודא שטעינת הערכים מתבצעת רק בהרצה הראשונה של הדף ולא אחרי כל פוסטבק: if not(ispostback) then טעינת הערכים end if
 
למעלה