Original text: Implementing Dynamic ItemTemplates
By: Scott Watermasysk
Published: 4/10/2002
Translation: Drason
Template controls allow users to create complex user interfaces without spending any time. Many controls use template technology (DataGrid is an example). These controls work well, and usually, templates can be saved as ascx files to increase reusability. It is very likely that you don't know how your control is laid out beforehand, and you need to dynamically add some templates to deal with different events.
Another advantage of using templates is that they can be dynamically added to your control. In this way, you can design the template in advance and then add it to your control with a few simple lines of code.
The following article will tell you how to add a dynamic ItemTemplate and EditItemTemplate step by step to DataGrid. In addition, it will also tell you how to get and update the changes made by users to EditItemTemplate. The example will be very simple. Then, I will soon officially release an improved TableEditor version on TripleASP. This version will better explain how to use dynamic templates.
Implementation of ITempalte
In order to dynamically add ItemTemplate and EditItemTemplate, we need to create two classes to implement the interface of ITemplate. The first class is GenericItem. The main work of this class is: take the column name of the data source, create a text control (literal contral), assign values to the text control, and finally add this text control to the parent control (here the parent control is DataGrid).
So far, it's been very smooth. Before continuing the discussion below, let's take a look at the code and the steps to complete.
using System;
using ;
using ; using ;
using ;
namespace
{
/// <summary>
/// Summary description for GenericItem.
/// </summary>
public class GenericItem : ITemplate
{
private string column;
//private bool validate;
public GenericItem(string column)
{
= column;
}
public void InstantiateIn(Control container)
{
Literal l = new Literal();
+= new EventHandler();
(l);
}
public void BindData(object sender, EventArgs e)
{
Literal l = (Literal) sender;
DataGridItem container = (DataGridItem) ;
= ((DataRowView) )[column].ToString();
}
}
}
As you can see, the GenericItem class implements the interface of ITemplate. Because we implement the interface, the InstantiateIn method must be included. This method is used to define the control objects to which all child controls and templates belong. In this method, we create a new Literal control to save the unit value of DataGrid. Next, we add the DataBinding event handling function. This event handling function actually puts the unit value into the Text property of the Literal control when DataGrid binds data. Finally, add this Literal control to the control's container collection. It's very simple?
Dynamic EditItemTemplate
The dynamic EditItemTemplate class ValidateEditItem is very similar to GenericItem, but there are 3 different places.
The first difference is that we add a Textbox control instead of a Literal control. In this way, in edit mode, the user can make any changes.
The second difference is that you will find that we will explicitly name the control. This will allow us to get any data changes in the update event.
The last difference is that you will see a RequiredFieldValidator control associated with Textbox. This is optional. However, this does let you know that some things can be done this.
Here is the code for ValidateEditItem:
using System;
using ;
using ;
using ;
using ;
namespace
{
/// <summary>
/// Summary description for ValidateEditItem.
/// </summary>
public class ValidateEditItem : ITemplate
{
private string column;
public ValidateEditItem(string column)
{
= column;
}
public void InstantiateIn(Control container)
{
TextBox tb = new TextBox();
+= new EventHandler();
(tb);
= column;
RequiredFieldValidator rfv = new RequiredFieldValidator();
= "Please Answer";
= ;
= ;
= "validate" + ;
(rfv);
}
public void BindData(object sender, EventArgs e)
{
TextBox tb = (TextBox) sender;
DataGridItem container = (DataGridItem);
= ((DataRowView) )[column].ToString();
}
}
}
Implementation of dynamic templates
Now we have two classes that implement the ITempalte interface. Everything is ready! All we have to do now is add them to our datagrid.
We put BindData and DynamicColumns together. BindData mainly creates SQL query statements, adds columns (dynamic columns) to datagrid, and then binds the data table to datagrid.
void BindData()
{
string sql = "Select * from publishers Where State Is not null";
(DynamicColumns("pub_id",false));
(DynamicColumns("pub_name",true));
(DynamicColumns("city",true));
(DynamicColumns("state",true));
(DynamicColumns("country",true));
= "pub_id";
= GetDataTable(sql);
();
}
DynamicColumns has two parameters: column (character type) and isEditable (boolean type). The column variable is of course the column name we want to add the TemplateColumn column name. The isEditable variable is used for testing, if we want this column to be edited.
protected TemplateColumn DynamicColumns(string column, bool isEditable)
{
TemplateColumn genericcolumn = new TemplateColumn();
= column;
= new GenericItem(column);
if(isEditable)
{
= new ValidateEditItem(column);
}
return genericcolumn;
}
As you can see, first we instantiate a TemplateColumn(genericcolumn), set the HeaderText property according to the name of the column we want to add (of course, you can set it to anything). Then, we add the ItemTemplate to genericcolumn by adding a new GenericItem reference (reference) and pass the name in. Finally, we have to check isEditable to see if we need to allow editing of this column. If true, we want to add a new reference to ValidateEditItem and pass the column names over.
DataGrid Event
Our editing and canceling events are very standard. You may have seen them 100 times. In our editing events, we simply take out the number of the selected rows and rebind the data.
protected void Edit_Click(Object sender, DataGridCommandEventArgs e)
{
= ;
BindData();
}
Our cancel event is to set the currently selected line number to -1. This is equivalent to telling datagrid that it is no longer in editing mode. Then, we rebind the data.
protected void Cancel_Click(Object sender, DataGridCommandEventArgs e)
{
= -1;
BindData();
}
The update event will be a little different from what you have seen before. However, it will remind you of your days in ASP.
protected void Update_Click(Object sender, DataGridCommandEventArgs e)
{
//Gets the UniqueID that is attached to the front of each textbox
//dyamically added to our datagrid's EditItemTempate
string uid = + ":";
string pub_id = (string)[];
string pub_name = ([uid + "pub_name"].ToString());
string city = ([uid + "city"].ToString());
string state = ([uid + "state"].ToString());
string country = ([uid + "country"].ToString());
//Simple method to update DB
UpdateRecord(pub_id,pub_name,city,state,country);
= -1;
BindData();
}
In this way, the EditItemTemplate is hardcoded into the page. You may have seen some examples of taking form submission data, including methods, either taking values through the control position or the control name. However, if you create a control at runtime, then you cannot get these values when PostBack. For this reason, we can only get these values through methods.
When you start carefully searching for carefully named textboxes in the ValidateEditItem class, you must remember that precautions have been taken for the name conflict of the control. Generally speaking, this includes adding the name of each datagrid parent control, the name of the datagrid itself, and a string representing the serial number of each textbox before the textbox ID. We can use this method in large quantities. But this does not guarantee that our code is absolutely modular and reusable. Instead, we check and add ":" to the end. With this UniqueID, we can safely obtain the edited data in the textbox and update it to the database.
in conclusion
Dynamically adding templates to your template controls will add a little workload at the beginning. However, once you build a series of excellent template classes, you will find that implementing ITemplate is very fast and easy. It runs you to build powerful controls to meet your data manipulation needs. If you need a better example, please see the TableEditor control I'm about to publish on TripleASP.
By: Scott Watermasysk
Published: 4/10/2002
Translation: Drason
Template controls allow users to create complex user interfaces without spending any time. Many controls use template technology (DataGrid is an example). These controls work well, and usually, templates can be saved as ascx files to increase reusability. It is very likely that you don't know how your control is laid out beforehand, and you need to dynamically add some templates to deal with different events.
Another advantage of using templates is that they can be dynamically added to your control. In this way, you can design the template in advance and then add it to your control with a few simple lines of code.
The following article will tell you how to add a dynamic ItemTemplate and EditItemTemplate step by step to DataGrid. In addition, it will also tell you how to get and update the changes made by users to EditItemTemplate. The example will be very simple. Then, I will soon officially release an improved TableEditor version on TripleASP. This version will better explain how to use dynamic templates.
Implementation of ITempalte
In order to dynamically add ItemTemplate and EditItemTemplate, we need to create two classes to implement the interface of ITemplate. The first class is GenericItem. The main work of this class is: take the column name of the data source, create a text control (literal contral), assign values to the text control, and finally add this text control to the parent control (here the parent control is DataGrid).
So far, it's been very smooth. Before continuing the discussion below, let's take a look at the code and the steps to complete.
using System;
using ;
using ; using ;
using ;
namespace
{
/// <summary>
/// Summary description for GenericItem.
/// </summary>
public class GenericItem : ITemplate
{
private string column;
//private bool validate;
public GenericItem(string column)
{
= column;
}
public void InstantiateIn(Control container)
{
Literal l = new Literal();
+= new EventHandler();
(l);
}
public void BindData(object sender, EventArgs e)
{
Literal l = (Literal) sender;
DataGridItem container = (DataGridItem) ;
= ((DataRowView) )[column].ToString();
}
}
}
As you can see, the GenericItem class implements the interface of ITemplate. Because we implement the interface, the InstantiateIn method must be included. This method is used to define the control objects to which all child controls and templates belong. In this method, we create a new Literal control to save the unit value of DataGrid. Next, we add the DataBinding event handling function. This event handling function actually puts the unit value into the Text property of the Literal control when DataGrid binds data. Finally, add this Literal control to the control's container collection. It's very simple?
Dynamic EditItemTemplate
The dynamic EditItemTemplate class ValidateEditItem is very similar to GenericItem, but there are 3 different places.
The first difference is that we add a Textbox control instead of a Literal control. In this way, in edit mode, the user can make any changes.
The second difference is that you will find that we will explicitly name the control. This will allow us to get any data changes in the update event.
The last difference is that you will see a RequiredFieldValidator control associated with Textbox. This is optional. However, this does let you know that some things can be done this.
Here is the code for ValidateEditItem:
using System;
using ;
using ;
using ;
using ;
namespace
{
/// <summary>
/// Summary description for ValidateEditItem.
/// </summary>
public class ValidateEditItem : ITemplate
{
private string column;
public ValidateEditItem(string column)
{
= column;
}
public void InstantiateIn(Control container)
{
TextBox tb = new TextBox();
+= new EventHandler();
(tb);
= column;
RequiredFieldValidator rfv = new RequiredFieldValidator();
= "Please Answer";
= ;
= ;
= "validate" + ;
(rfv);
}
public void BindData(object sender, EventArgs e)
{
TextBox tb = (TextBox) sender;
DataGridItem container = (DataGridItem);
= ((DataRowView) )[column].ToString();
}
}
}
Implementation of dynamic templates
Now we have two classes that implement the ITempalte interface. Everything is ready! All we have to do now is add them to our datagrid.
We put BindData and DynamicColumns together. BindData mainly creates SQL query statements, adds columns (dynamic columns) to datagrid, and then binds the data table to datagrid.
void BindData()
{
string sql = "Select * from publishers Where State Is not null";
(DynamicColumns("pub_id",false));
(DynamicColumns("pub_name",true));
(DynamicColumns("city",true));
(DynamicColumns("state",true));
(DynamicColumns("country",true));
= "pub_id";
= GetDataTable(sql);
();
}
DynamicColumns has two parameters: column (character type) and isEditable (boolean type). The column variable is of course the column name we want to add the TemplateColumn column name. The isEditable variable is used for testing, if we want this column to be edited.
protected TemplateColumn DynamicColumns(string column, bool isEditable)
{
TemplateColumn genericcolumn = new TemplateColumn();
= column;
= new GenericItem(column);
if(isEditable)
{
= new ValidateEditItem(column);
}
return genericcolumn;
}
As you can see, first we instantiate a TemplateColumn(genericcolumn), set the HeaderText property according to the name of the column we want to add (of course, you can set it to anything). Then, we add the ItemTemplate to genericcolumn by adding a new GenericItem reference (reference) and pass the name in. Finally, we have to check isEditable to see if we need to allow editing of this column. If true, we want to add a new reference to ValidateEditItem and pass the column names over.
DataGrid Event
Our editing and canceling events are very standard. You may have seen them 100 times. In our editing events, we simply take out the number of the selected rows and rebind the data.
protected void Edit_Click(Object sender, DataGridCommandEventArgs e)
{
= ;
BindData();
}
Our cancel event is to set the currently selected line number to -1. This is equivalent to telling datagrid that it is no longer in editing mode. Then, we rebind the data.
protected void Cancel_Click(Object sender, DataGridCommandEventArgs e)
{
= -1;
BindData();
}
The update event will be a little different from what you have seen before. However, it will remind you of your days in ASP.
protected void Update_Click(Object sender, DataGridCommandEventArgs e)
{
//Gets the UniqueID that is attached to the front of each textbox
//dyamically added to our datagrid's EditItemTempate
string uid = + ":";
string pub_id = (string)[];
string pub_name = ([uid + "pub_name"].ToString());
string city = ([uid + "city"].ToString());
string state = ([uid + "state"].ToString());
string country = ([uid + "country"].ToString());
//Simple method to update DB
UpdateRecord(pub_id,pub_name,city,state,country);
= -1;
BindData();
}
In this way, the EditItemTemplate is hardcoded into the page. You may have seen some examples of taking form submission data, including methods, either taking values through the control position or the control name. However, if you create a control at runtime, then you cannot get these values when PostBack. For this reason, we can only get these values through methods.
When you start carefully searching for carefully named textboxes in the ValidateEditItem class, you must remember that precautions have been taken for the name conflict of the control. Generally speaking, this includes adding the name of each datagrid parent control, the name of the datagrid itself, and a string representing the serial number of each textbox before the textbox ID. We can use this method in large quantities. But this does not guarantee that our code is absolutely modular and reusable. Instead, we check and add ":" to the end. With this UniqueID, we can safely obtain the edited data in the textbox and update it to the database.
in conclusion
Dynamically adding templates to your template controls will add a little workload at the beginning. However, once you build a series of excellent template classes, you will find that implementing ITemplate is very fast and easy. It runs you to build powerful controls to meet your data manipulation needs. If you need a better example, please see the TableEditor control I'm about to publish on TripleASP.