I have an ASP.NET page with a FormView data-bound to an ObjectDataSource that uses dynamically generated templates to render the UI based on layout information from the application's database. I've been able to get the templates to render correctly and everything seems fine until I click one of the buttons to change modes - nothing changes.
My code is based on the explanations provided in the following articles/posts:
http://www.codeproject.com/KB/aspnet/DynamicFormview.aspx
http://msdn.microsoft.com/en-us/library/ms227423.aspx
http://msdn.microsoft.com/en-us/library/y0h809ak(vs.71).aspx
In a nutshell, in the Page.OnInit method I assign an instance of my templates to the FormView EditItemTemplate, EmptyDataTemplate, InsertItemTemplate and ItemTemplate properties (a different instance for each property with the appropriate controls, layout, etc for that template). I see that the InstantiateIn method of the template corresponding to the default mode is called, the control hierarchy is created correctly and the UI rendered as expected.
I have a set of button controls in each of my templates that enable the mode switches. So, for instance, in the ItemTemplate, I have a button with CommandName="New". I expect that clicking this button will cause the FormView to change into the Insert mode. Instead, I get the postback and InstantiateIn is called on my ItemTemplate. The handlers I've attached to the FormView's ModeChanging and ModeChanged events do not fire.
When I step through the control hierarchy, I see the same object model as the page I created in markup - with one exception. I am using the HtmlTable, HtmlTableRow and HtmlTableCell controls to construct the layout whereas the markup uses <table>, <tr> and <td> elements.
Any thoughts on what I'm missing? I'd really like to get this working with the automatic binding (through event bubbling) to change modes rather than have to manually create and code the buttons and their actions.
Here is the code used to generate the template:
public class FormViewTemplate : INamingContainer, ITemplate
{
private Boolean _childControlsCreated;
private Panel _panel;
public FormViewTemplate(TemplateMode mode) { Mode = mode; }
public TemplateMode Mode { get; private set; }
private void CreateChildControls()
{
_panel = new Panel();
_panel.Controls.Add(CreateButtons());
switch (Mode)
{
case TemplateMode.Edit:
_panel.Controls.Add(new LiteralControl("Edit Mode"));
break;
case TemplateMode.Empty:
_panel.Controls.Add(new LiteralControl("Empty Mode"));
break;
case TemplateMode.Insert:
_panel.Controls.Add(new LiteralControl("Insert Mode"));
break;
case TemplateMode.ReadOnly:
_panel.Controls.Add(new LiteralControl("Read-Only Mode"));
break;
}
}
private Panel CreateButtons()
{
var panel = new Panel();
var table = new HtmlTable()
{
Border = 0,
CellPadding = 2,
CellSpacing = 0
};
panel.Controls.Add(table);
var tr = new HtmlTableRow();
table.Rows.Add(tr);
var td = new HtmlTableCell();
tr.Cells.Add(td);
var addButton = new ASPxButton()
{
CommandName = "New",
Enabled = (Mode == TemplateMode.ReadOnly),
ID = "AddButton",
Text = "Add"
};
td.Controls.Add(addButton);
return panel;
}
private void EnsureChildControls()
{
if (!_childControlsCreated)
{
CreateChildControls();
_childControlsCreated = true;
}
}
void ITemplate.InstantiateIn(Control container)
{
EnsureChildControls();
container.Controls.Add(_panel);
}
}
(Note that the template is cached so the control hierarchy is only built once.)