您的位置:首页 > 其它

动态添加DataGrid模板列(英)

2005-03-12 22:35 531 查看
Implementing Dynamic ItemTemplates By: Scott Watermasysk
Published: 4/10/2002
Printer Friendly
Download

Template controls allow a developer to set up a complicated user interface in almost no time at all. ASP.Net has a couple of controls that use templates (the Datagrid is a prime example). While this works great, and often used templates can be saved as .ascx files to enhance reusability, there will likely be times where the layout of your control isn't known a head of time and you need to dynamically add a template based on different events.

One of the other great advantages to using templates, is they can be added to your controls dynamically. This way, you can design very detailed templates and add them to any of your templated controls with just a couple of lines of code.

The following article is going to walk you through the steps of adding a dynamic ItemTemplate and EditItemTemplate to a datagrid. In addition, it is going to show you how to retrieve and update any changes made by the user in the EditItemTemplate. This example will be fairly simple. However, I will soon be releasing a much-improved version of the TripleASP TableEditor, which will serve as a better example of what can be accomplished using dynamic templates.

Implementing ITemplate

In order for us to dynamically add our ItemTemplate and EditItemTemplate we are going to have to create two classes that implement the ITemplate interface. The first of these classes, GenericItem, simply takes the name of our data source's column, creates a literal control, adds the data source value to the literal control, and then adds the literal control to the parent control, which in this case, is our datagrid.

This was a very quick run down. Before we continue, lets take a quick look at the code, and see the steps it took to get this action completed.
using System;
using System.Web;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TripleASP.ItemTemplates
{
/// <summary>
/// Summary description for GenericItem.
/// </summary>
public class GenericItem : ITemplate
{
private string column;
//private bool validate;
public GenericItem(string column)
{
this.column = column;
}
public void InstantiateIn(Control container)
{
Literal l = new Literal();
l.DataBinding += new EventHandler(this.BindData);
container.Controls.Add(l);
}

public void BindData(object sender, EventArgs e)
{
Literal l = (Literal) sender;
DataGridItem container = (DataGridItem) l.NamingContainer;
l.Text = ((DataRowView) container.DataItem)[column].ToString();

}
}
}
As you can see our GenericItem class implements the ITemplate interface. Because we are implementing the ITemplate interface in this class, we must include the method, InstantiateIn, which defines the Control object that child controls and templates belong to. In the InstantiateIn method, we are creating a new Literal control, which will hold the individual datagrid cell value. Next, we wire up a DataBinding event, which will actually add the cells value to the Text property of our Literal control when the parent datagrid's DataBind method is called. Finally, we add the Literal control to the control collection of our container control. Pretty Simple!

Dynamic EditItemTemplate

The dynamic EditItemTemplate class, ValidateEditItem, is the same as the GenericItem class with three key exceptions. The first difference you will notice is that we are now adding a textbox to the control collection instead of a literal control. This way, during edit mode, a user can make any applicable changes.
The second major difference you will notice is that we took the time to explicitly name (through the ID property) our control. This will help us retrieve any data changes made during the update event.
The third and final difference you will see is that we added a RequiredFieldValidator and connected it to our textbox. This is of course optional, but it does begin to show you how handy something like this could be.
Here is our ValidateEditItem class:
using System;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web;

namespace TripleASP.ItemTemplates
{
/// <summary>
/// Summary description for ValidateEditItem.
/// </summary>
public class ValidateEditItem : ITemplate
{
private string column;
public ValidateEditItem(string column)
{
this.column = column;
}

public void InstantiateIn(Control container)
{
TextBox tb = new TextBox();
tb.DataBinding += new EventHandler(this.BindData);
container.Controls.Add(tb);
tb.ID = column;

RequiredFieldValidator rfv = new RequiredFieldValidator();
rfv.Text = "Please Answer";
rfv.ControlToValidate = tb.ID;
rfv.Display = ValidatorDisplay.Dynamic;
rfv.ID = "validate" + tb.ID;
container.Controls.Add(rfv);

}

public void BindData(object sender, EventArgs e)
{
TextBox tb = (TextBox) sender;
DataGridItem container = (DataGridItem)tb.NamingContainer;
tb.Text = ((DataRowView) container.DataItem)[column].ToString();
}
}
}

Implementing the Dynamic Template

We now have our two classes that implement the ITemplate int
4000
erface built and ready to go. All that we have to do now is add them to our datagrid.

We will quickly put together two methods, BindData and DynamicColumns. BindData will create our SQL querystring, add each of our datagrid's columns (using DynamicColumns), and then bind our datatable to the datagrid.
void BindData()
{
string sql = "Select * from publishers Where State Is not null";
DataGrid1.Columns.Add(DynamicColumns("pub_id",false));
DataGrid1.Columns.Add(DynamicColumns("pub_name",true));
DataGrid1.Columns.Add(DynamicColumns("city",true));
DataGrid1.Columns.Add(DynamicColumns("state",true));
DataGrid1.Columns.Add(DynamicColumns("country",true));
DataGrid1.DataKeyField = "pub_id";
DataGrid1.DataSource = GetDataTable(sql);
DataGrid1.DataBind();
}
The DynamicColumns method has two parameters: column (a string) and isEditable (a bool). The column variable will of course be the name of the column we wish to add to our TemplateColumn and the isEditable variable will be used to test, if we wish, to allow this column to be edited within our datagrid. INSERT DYNAMICCOLUMNS
protected TemplateColumn DynamicColumns(string column, bool isEditable)
{
TemplateColumn genericcolumn = new TemplateColumn();
genericcolumn.HeaderText = column;
genericcolumn.ItemTemplate = new GenericItem(column);
if(isEditable)
{
genericcolumn.EditItemTemplate = new ValidateEditItem(column);
}
return genericcolumn;
}
As you can see, we will first instantiate a new TemplateColumn, genericcolumn, set its HeaderText property to the name of the column we are about to add (You can of course set this to anything you like, but to keep it simple, we chose to set it to the column name). Next we add the ItemTemplate to the genericcolumn by adding a new reference to our GenericItem class and passing it the name of our column. Finally we check our isEditable bool to see if we would like to allow editing on this column. If true, we add a new reference to our ValidateEditItem and again pass along the name of the column we are adding to the datagrid.

The DataGrid Events

Our edit and cancel events are very standard and you have likely seen them 100's of times. In our edit event we simply retrieve the index number of the row selected to be edited, and then rebind our data.
protected void Edit_Click(Object sender, DataGridCommandEventArgs e)
{
DataGrid1.EditItemIndex = e.Item.ItemIndex;
BindData();
}
Our cancel event simply sets the currently selected row to -1, which tells our datagrid that we are no longer in edit mode, and then again, rebind our data.
protected void Cancel_Click(Object sender, DataGridCommandEventArgs e)
{
DataGrid1.EditItemIndex = -1;
BindData();
}
The update event will be a little different from most of the other examples you have seen on updating data in a datagrid. However, it will definitely remind you of your days in classic 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 = e.Item.UniqueID + ":";

string pub_id = (string)DataGrid1.DataKeys[e.Item.ItemIndex];
string pub_name = (Request.Form[uid + "pub_name"].ToString());
string city = (Request.Form[uid + "city"].ToString());
string state = (Request.Form[uid + "state"].ToString());
string country = (Request.Form[uid + "country"].ToString());

//Simple method to update DB
UpdateRecord(pub_id,pub_name,city,state,country);
DataGrid1.EditItemIndex = -1;
BindData();
}
In situations where the EditItemTemplate is hard coded into the page, you would have likely seen examples of retrieving the posted back data by either referencing the controls location (DataGridCommandEventArgs.Item.Cells[]Controls[]) or by finding the control by name (DataGridCommandEventArgs.Item.FindControl). However, if you create controls at runtime then ASP.NET can't create them for you when you do a postback. Thus, in order to retrieve our updated values, we need to take a step back into the past and use the Request.Forms collection.

Before you jump in and start trying to find the textboxes we so carefully named in our ValidateEditItem class, you have to remember that ASP.Net takes a precautionary step to make sure the names of our controls do not clash with one another. In general, this involves adding the name of each of our datagrid's parent controls, the name of our datagrid itself, and a string representing the control index of each textbox to the beginning of each textboxes' ID property. We could hard code a large part of this, but it would not allow our code to be as modular and reusable as possible. Instead, we check the DataGridCommandEventArgs.Item.UniqueID property and add an extra ":" to the end of it. Armed with the UniqueID we can safely retrieve the values we changed in our textboxes during edit mode, and update our database.

Conclusion

Dynamically adding Templates to your templated controls takes a little more work to set up the first time. But once you have built a couple of good template classes, you will find that implementing the ITemplate interface can be done quickly and easily. Which will allow you building powerful controls to handle a great deal of your routine data needs. For a better example of this, please watch out for the upcoming release of the TripleASP TableEditor control.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息