Description:
Templates are widely used among our components. Be it the grid's DataItem template or the menu's Item template, all the templates share one common thing - elements inside them are nested in template containers. This article describes how to work with them in different situations.
Answer:
These containers store values that are useful during custom template processing. E.g., you can obtain the current visible index, column, and key value in the grid's DataItem template or obtain the current node in the treeview's Node template.
The container's type usually has the following pattern:
[The control's name without the "ASPx" prefix][The template's name]TemplateContainer
Thus, elements in the grid's DetailRow template are nested in the container of the GridViewDetailRowTemplateContainer type.
Now when we know the container's type, we can obtain the object that represents the container by casting the control's NamingContainer property to the container's type:
C#protected void txtName_Init(object sender, EventArgs e){
ASPxTextBox txtName = (ASPxTextBox)sender;
GridViewEditFormTemplateContainer container = txtName.NamingContainer as GridViewEditFormTemplateContainer;
}
Visual BasicProtected Sub txtName_Init(ByVal sender As Object, ByVal e As EventArgs)
Dim txtName As ASPxTextBox = CType(sender, ASPxTextBox)
Dim container As GridViewEditFormTemplateContainer = TryCast(txtName.NamingContainer, GridViewEditFormTemplateContainer)
End Sub
If, for any reason, the "container" object is null, you can always place a breakpoint in your code and see the container's type manually in the VS Watch window.
Example #1
The most common example is when you want to place your own controls in the grid's DataItem template and bind them to some values. This scenario is described in the The general technique of using the Init/Load event handler article.
If, however, it is necessary to update the underlying datasource as soon as the user enters a new value into the editor, it is possible to obtain the row's key value and the column's FieldName property from the container. Send these values via a callback to the server:
C#protected void txtID_Init(object sender, EventArgs e) {
ASPxTextBox tb = sender as ASPxTextBox;
GridViewDataItemTemplateContainer container = tb.NamingContainer as GridViewDataItemTemplateContainer;
//...
tb.ClientSideEvents.ValueChanged = String.Format("function (s,e) {{ SendCallback('{0}','{1}', s.GetValue()); }}",
container.Column.FieldName,
container.KeyValue);
}
Visual BasicProtected Sub txtID_Init(ByVal sender As Object, ByVal e As EventArgs)
Dim tb As ASPxTextBox = TryCast(sender, ASPxTextBox)
Dim container As GridViewDataItemTemplateContainer = TryCast(tb.NamingContainer, GridViewDataItemTemplateContainer)
'...
tb.ClientSideEvents.ValueChanged = String.Format("function (s,e) {{ SendCallback('{0}','{1}', s.GetValue()); }}", container.Column.FieldName, container.KeyValue)
End Sub
This approach is illustrated in the How to perform ASPxGridView instant updating using different editors in the DataItem template example.
Usually, if ASPxGridView is bound to a collection of an objects (either directly or via the ObjectDataSource component), you might need to obtain the object that corresponds to the current row. You can easily accomplish this task by using the ASPxGridView.GetRow method. For example:
C#protected void txtName_Init(object sender, EventArgs e) {
ASPxTextBox txtName = (ASPxTextBox)sender;
GridViewEditFormTemplateContainer container = txtName.NamingContainer as GridViewEditFormTemplateContainer;
Invoice currentObject = container.Grid.GetRow(container.VisibleIndex) as Invoice;
//...
}
Visual BasicProtected Sub txtName_Init(ByVal sender As Object, ByVal e As EventArgs)
Dim txtName As ASPxTextBox = DirectCast(sender, ASPxTextBox)
Dim container As GridViewEditFormTemplateContainer = TryCast(txtName.NamingContainer, GridViewEditFormTemplateContainer)
Dim currentObject As Invoice = TryCast(container.Grid.GetRow(container.VisibleIndex), Invoice)
'...
End Sub
Invoice here is the class name of the custom object which list is used as an ASPxGridView datasource.
Example #2
Another common scenario is when it is necessary to create a template dynamically. Assume we have an ASPxDataView control. It is necessary to generate each item dynamically based on some value. E.g., we have the Employees database and it is necessary to add the ASPxTreeList control to display all subordinates for an employee whose EmployeePosition value isn't "SalesManager". Otherwise, the treelist should not be added. To accomplish this, we obtain DataViewItemTemplateContainer and use its EvalDataItem method:
C#public class CustomItemTemplate : ITemplate {
public void InstantiateIn(Control container) {
DataViewItemTemplateContainer dvContainer = container as DataViewItemTemplateContainer;
//...
string position = dvContainer.EvalDataItem("EmployeePosition").ToString();
if (position != "SalesManager") {
ASPxTreeList subordinatesTree = new ASPxTreeList();
subordinatesTree.ID = "tree" + dvContainer.ItemIndex;
container.Controls.Add(subordinatesTree);
//...
}
}
}
Visual BasicPublic Class CustomItemTemplate
Implements ITemplate
Public Sub InstantiateIn(ByVal container As Control)
Dim dvContainer As DataViewItemTemplateContainer = TryCast(container, DataViewItemTemplateContainer)
'...
Dim position As String = dvContainer.EvalDataItem("EmployeePosition").ToString()
If position <> "SalesManager" Then
Dim subordinatesTree As New ASPxTreeList()
subordinatesTree.ID = "tree" & dvContainer.ItemIndex
container.Controls.Add(subordinatesTree)
'...
End If
End Sub
End Class
See Also:
The general technique of using the Init/Load event handler
How to create controls dynamically