Hello,
I am trying to build an ASPxGridView that uses different ASPx controls in the editor depending on the type of data being edited (text, Char, List or DateTime. I can't use the EditForm template because the edit controls can't be known at design time.
I am using an unbound column in the grid to display/edit the data item. I am handling the different control types in the grid view's "CellEditorInitialize" event handler.
protected void PDRReferencesGrid_CellEditorInitialize(object sender, ASPxGridViewEditorEventArgs e)
{
ASPxGridView gv = (ASPxGridView)sender;
if (e.Column.FieldName == "PDR_VALUE")
{
int key = Convert.ToInt16(e.KeyValue);
PlaceHolder control = new PlaceHolder();
control.ID = "PDRPlaceHolder";
string dataType = Convert.ToString(gv.GetRowValuesByKeyValue(key, "DATA_TYPE_NAME"));
char required = Convert.ToChar(gv.GetRowValuesByKeyValue(key, "MANDATORY_IND"));
switch (dataType)
{
case "String":
ASPxTextBox tb = new ASPxTextBox();
tb.ID = "PDRValue";
tb.ValidationSettings.RequiredField.IsRequired = required == 'Y';
tb.ValidationSettings.ValidateOnLeave = true;
tb.ValidationSettings.CausesValidation = tb.ValidationSettings.RequiredField.IsRequired;
tb.ValidationSettings.ErrorDisplayMode = ErrorDisplayMode.ImageWithText;
tb.ValidationSettings.ErrorText = "Required";
control.Controls.Add(tb);
break;
case "Date":
ASPxDateEdit de = new ASPxDateEdit();
de.ID = "PDRValue";
de.ValidationSettings.RequiredField.IsRequired = required == 'Y';
control.Controls.Add(de);
break;
case "DateTime":
ASPxDateEdit dte = new ASPxDateEdit();
ASPxTextEdit tte = new ASPxTimeEdit();
dte.ID = "PDRValue_Date";
dte.ValidationSettings.RequiredField.IsRequired = required == 'Y';
tte.ID = "PDRValue_Time";
tte.ValidationSettings.RequiredField.IsRequired = dte.ValidationSettings.RequiredField.IsRequired;
control.Controls.Add(dte);
control.Controls.Add(tte);
break;
case "Char":
ASPxCheckBox cb = new ASPxCheckBox();
cb.ID = "PDRValue";
cb.ValueUnchecked = 'N';
cb.ValueChecked = 'Y';
cb.ValidationSettings.RequiredField.IsRequired = required == 'Y';
control.Controls.Add(cb);
break;
case "List":
List<String> demoList = new List<String>();
demoList.Add("A list item for demo");
ASPxListBox lb = new ASPxListBox();
lb.ID = "PDRValue";
lb.ValidationSettings.RequiredField.IsRequired = required == 'Y';
lb.DataSource = demoList;
lb.DataBind();
control.Controls.Add(lb);
break;
}
e.Editor.Controls.Add(control);
}
}
Three questions:
- Is this the best place to handle the dynamic control creation?
- How do I disable the inclusion of the default TextField presented by the editor when in edit mode (attached)?
- Does the gridview only support a single ITemplate interface or could I have added an ITemplate interface at the GridViewEditCell level? Something like:
public class StringEditFormTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
ASPxTextBox tb = new ASPxTextBox();
tb.ID = "PDRValue_String";
container.Controls.Add(tb);
}
}
public class DateEditFormTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
ASPxDateEdit de = new ASPxDateEdit();
de.ID = "PDRValue_Date";
container.Controls.Add(de);
}
}
public class DateTimeEditFormTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
ASPxDateEdit de = new ASPxDateEdit();
ASPxTimeEdit te = new ASPxTimeEdit();
de.ID = "PDRValue_Date";
te.ID = "PDRValue_Time";
container.Controls.Add(de);
container.Controls.Add(te);
}
}
public class CharEditFormTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
ASPxCheckBox cb = new ASPxCheckBox();
cb.ID = "PDRValue_Char";
container.Controls.Add(cb);
}
}
public class ListEditFormTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
DropDownList ddl = new DropDownList();
ddl.ID = "PDRValue_List";
container.Controls.Add(ddl);
}
}
Hello Grant,
Thank you for the detailed question. In fact, you approach is interesting, but unfortunately it isn't correct :( The ASPxGridView.CellEditorInitialize event should be used for standard (created by the grid) editors only.
That is why you have the default ASPxTextBox being shown when the grid is switched to the edit mode.
The most appropriate solution depends on how you determine which template should be loaded. Usually I recommend the following approach:
You can create the one ITemplate class, which creates all four editors in the InstantiateIn method. There you can analyze the "container" property (it should be the GridViewEditCellTemplateContainer) to get grid's instance and editing row key. Then you'll be able to determine via your custom logic which editor should be created (or be visible).
The ASPxGridView doesn't allow you to have multiple templates, but you can create one template, which layout might depend on certain conditions.
Thanks,
Vest
Thanks for your very fast reply.
I considered both creating all controls in the unbound column as well as creating a single ITemplate class that predefines the controls but didn't want the overhead associated with hiding those controls I didn't want (I only need one per edit row).
If I'm understanding your solution correctly, the best method is to create a class implementing the ITemplate interface and adding all controls to this class? Is this any different than adding the controls to the edit form in terms of rendering perfromance?
When I added the following code, the new editform interface didn't render (either inline or editform)
protected void PDRReferencesGrid_Init(object sender, EventArgs e)
{
ASPxGridView gv = (ASPxGridView)sender;
gv.Templates.EditForm = new PDRReferencesEditFormTemplate();
}
public class PDRReferencesEditFormTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
ASPxDateEdit de = new ASPxDateEdit();
de.ID = "PDRValue_Date";
container.Controls.Add(de);
AddControls(container);
}
protected void AddControls(Control container){
AddTextBox(container);
AddDateEdit(container);
AddTimeEdit(container);
AddCheckBox(container);
AddListBox(container);
}
protected void AddTextBox(Control container)
{
ASPxTextBox tb = new ASPxTextBox();
tb.ID = "PDRValue_String";
container.Controls.Add(tb);
}
protected void AddDateEdit( Control container)
{
ASPxDateEdit de = new ASPxDateEdit();
de.ID = "PDRValue_Date";
container.Controls.Add(de);
}
protected void AddTimeEdit( Control container)
{
ASPxTimeEdit te = new ASPxTimeEdit();
te.ID = "PDRValue_Time";
container.Controls.Add(te);
}
protected void AddCheckBox( Control container)
{
ASPxCheckBox cb = new ASPxCheckBox();
cb.ID = "PDRValue_Char";
container.Controls.Add(cb);
}
protected void AddListBox( Control container)
{
DropDownList ddl = new DropDownList();
ddl.ID = "PDRValue_List";
container.Controls.Add(ddl);
}
}
Sorry, the last code snippet for the ITemplate interface included a temp code snippet for debugging. Please swap out the code in the InstantiateIn method with the call to AddControls(container).
Thanks.
Should just have ;
public void InstantiateIn(Control container)
{
AddControls(container);
}