Creating RequiredFieldValidator for DetailsView dynamically
אחד מהפקדים הנחמדים לעבוד עם מידע הוא ה - DetailsView, הוא יודע להציג מידע לאורך במקום לרוחב (כמו Grid) ומתאים מאוד לעידכון של שורה אחת.
בדרך כלל מה שאני עושה זה להציג Grid עם כל הנתונים וכשבוחרים שורה מתוך ה - Grid אני מציג את הנתונים של אותה שורה ב - DetailsView.
לאחרונה רציתי לעבוד איתו בצורה דינמית כלומר - לא להגדיר מראש ב - aspx את כל העמודות. ורציתי להוסיף לאחד העמודות RequiredFieldValidator. נשמע פשוט לא, אז נראה את הקוד.
בהתחלה אני מקשר טבלה (עם שורה אחת) ל DetailsView
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Bind();
}
}
private void Bind()
{
DataTable dt = GetTable();
DetailsView1.DataSource = dt;
DetailsView1.DataBind();
}
private DataTable GetTable()
{
if (Session["table"] == null)
{
DataTable dt = new DataTable();
dt.Columns.Add("Id");
dt.Columns.Add("Name");
dt.Columns.Add("Age");
dt.Columns.Add("Salary");
dt.Rows.Add(1, "Ron", 40, 5000);
Session["table"] = dt;
}
return (DataTable)Session["table"];
}
ונרשמתי לאירוע של ModeChanging וכתבתי את הקוד הבא.
protected void DetailsView1_ModeChanging(object sender, DetailsViewModeEventArgs e)
{
DetailsView1.ChangeMode(e.NewMode);
Bind();
TextBox txtId = DetailsView1.Rows[0].Cells[1].Controls[0] as TextBox;
RequiredFieldValidator rfv = new RequiredFieldValidator();
rfv.ControlToValidate = txtId.ID;
rfv.ErrorMessage = "Required";
DetailsView1.Rows[0].Cells[1].Controls.Add(rfv);
}
כשהרצתי את הקוד הזה קבלתי את התוצאה הבאה.
"The ControlToValidate property of '' cannot be blank."
כשהסתכלתי ב - debugger ראיתי שאמנם המאפיין ID של txtId הוא null, מה שמעניין שברגע שהסתכלתי ב - watch על המאפיין היה לו ערך. כלומר עם הייתי כותב ב - watch את הדבר הבא - txt.ID הייתי מקבל null אבל עם הייתי כותב txt ומתחיל ללחוץ על סימן ה + כדי לראות את המאפיינים הייתי רואה במאפיין ID ערך (וכמובן שמאותו רגע גם הפקודה txt.ID החזירה ערך. ובמילים אחרות ה - ID של הפקד מתרנדר רק כשמסתכלים ב - watch, (או כשהדף נטען) זה נקודה מאוד לא ברורה ואני אחקור אותה כדי להבין מה קורה כאן, מהסתכלות קטנה ב - reflector אני רואה את הקוד הבא
public virtual string ID
{
get
{
if (!this.flags[1] && !this.flags[0x800])
{
return null;
}
return this._id;
}
set
{
// ...
}
}
אני לא מבין כרגע למה אם המערך במקום 1 וגם במקום 2048 הוא false הם מחזירים null, וזה נקודה שאני אבדוק בהזדמנות אחרת.
הפיתרון שכרגע השתמשתי היה לכתוב את הדבר הבא.
protected void DetailsView1_ModeChanging(object sender, DetailsViewModeEventArgs e)
{
DetailsView1.ChangeMode(e.NewMode);
Bind();
TextBox txtId = DetailsView1.Rows[0].Cells[1].Controls[0] as TextBox;
RequiredFieldValidator rfv = new RequiredFieldValidator();
string id = txtId.ClientID.Substring(txtId.ClientID.LastIndexOf('_') + 1);
rfv.ControlToValidate = rfv.ControlToValidate = id;
rfv.ErrorMessage = "Required";
DetailsView1.Rows[0].Cells[1].Controls.Add(rfv);
}
מתברר שהמאפיין ClientID כן מאותחל מראש בערך שלו, אז אני פשוט מוציא ממנו את ה - ID שהפקד יקבל בזמן שהוא יתרנדר.
נקודה נוספת שגיליתי (ואני צריך להבין אותה) שחייבים להוסיף את ה - Validator ל - Collection הבא: DetailsView1.Rows[0].Cells[1].Controls
אבל עם ננסה להוסיף את ה - Validator ל - Collection של ה - Form. נקבל את השגיאה הבאה.
Control 'ctl01' referenced by the ControlToValidate property of '' cannot be validated.
אני מקווה שאני אצליח למצוא את הסיבות לשני הדברים.
1. מה המשמעות של הקוד במאפיין ID.
2. למה אי אפשר להוסיף את ה - Validator ל - Collection של ה - Form.
דרך אגב. בקוד של המאפיין ID היה כתוב 0x800, ואני הצגתי את הערך העשרוני שלו 2048. השתמשתי עם השירות של גוגל.
פשוט כתבתי בגוגל: 0x800 in decimal וזה החזיר תוצאה.
ממש נחמד לעבוד איתו כדי להמיר מספרים. כמו
10 in binary