您的位置:首页 > 其它

为DataGrid创建自定义列控件

2008-05-03 17:44 288 查看
  DataGrid中为我们提供了5种常用的列控件

? BoundColumn
? ButtonColumn
? EditCommandColumn
? HyperLinkColumn
? TemplateColumn

  通常情况下,这5种列控件都能够完成我们大部分的开发,但是有时遇到特殊情况下,为了简化开发,自定义列控件就派上的用场。

  在开发以前,让我们先来了解下列控件的基础知识:

  所有的列控件都是来自System.Web.UI.WebControls命名空间,比如BoundColumn来自System.Web.UI.WebControls.BoundColumn命名空间。所有的这些控件都来自DataGridColumn类。

  DataGridColumn类具有的属性:

FooterStyle 获取列的脚注部分的样式属性。
FooterText 获取或设置列的脚注部分中显示的文本。
HeaderImageUrl 获取或设置列的页眉节中显示的图像的位置。
HeaderStyle 获取列的页眉节的样式属性。
HeaderText 获取或设置在列的页眉节中显示的文本。
ItemStyle 获取列的项单元格的样式属性。
SortExpression 获取或设置选择进行排序的列时传递到 OnSortCommand 方法的字段或表达式的名称。
Visible 获取或设置一个值,该值指示此列在 DataGrid 控件中是否可见。

DataGridColumn类有两个很重要的方法必须提出,一是Initialize方法,二是InitializeCell方法。Initialize方法提供基实现以将从 DataGridColumn 类派生的列重置为它的初始状态。InitializeCell 方法提供基实现以将从 DataGridColumn 类派生的列中的指定单元格重置为它的初始状态。(具体这两个方法的说明请大家自行查阅)

  好了,说了那么多废话,让我们马上进入到自定义列控件的开发。

  我们先来做一个非常简单的列控件,功能就是显示指定的文字。

  首先创建一个类库项目,命名为SimpleColumn,然后创建继承自DataGridColumn类的HelloColumn类,代码如下:

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace SimpleColumn
{
/**//// <summary>
/// Class1 的摘要说明。
/// </summary>
public class HelloColumn : DataGridColumn
{
public override void InitializeCell(TableCell cell, int columnIndex, ListItemType itemType)
{
base.InitializeCell (cell, columnIndex, itemType);
if((itemType == ListItemType.AlternatingItem)||(itemType == ListItemType.SelectedItem)||(itemType == ListItemType.Item))
{
cell.Text = "Hello";
}
}

}
}

  最后在页面上引用这各类

<%@ Register TagPrefix="custCols" Namespace="SimpleColumn" Assembly="SimpleColumn" %>

在DataGrid中添加Column,如下:

<Columns>
<custcols:HelloColumn></custcols:HelloColumn>
</Columns>
  最后效果:


  这样一个简单的自定义列控件就创建好了,是不是很简单呢?由于是继承DataGridColumn类,所以在显示的时候大家还可以设置这个列控件的页眉文字等属性。

  接下来,我们再来创建一个带自定义属性的列控件。这个列控件主要完成的任务就是可以自定义文字的显示个数,多余的部分用…显示,相信大家经常遇到这样的情况吧。

  首先我们创建一个继承自BoundColumn类的LimitColumn类。BoundColumn类继承自DataGridColumn类,用来显示数据源中的字段内容。LimitColumn控件将会用到BoundColumn类中的FormatDataValue方法,此方法用来指定显示字段内容的格式。

  然后设置自定义字数属性CharLimit,具体代码如下:

public class LimitColumn : BoundColumn
{
private int m_CharLimit = -1;
public int CharLimit
{
get
{
return this.m_CharLimit;
}
set
{
if(value>=0)
{
this.m_CharLimit = value;
}
else
{
this.m_CharLimit = -1;
}
}
}

protected override string FormatDataValue(object dataValue)
{
if(this.m_CharLimit == -1)
{
return base.FormatDataValue (dataValue);
}
else
{
string defValue = base.FormatDataValue (dataValue);
if(defValue.Length < this.m_CharLimit)
{
return defValue;
}
else
{
return defValue.Substring(0,this.m_CharLimit)+"";
}
}
}

  在页面上设置:

<Columns>
<custcols:LimitColumn CharLimit="2" DataField="ShipCountry"></custcols:LimitColumn>
</Columns>

  效果如下:


  通过这两个简单的例子,相信大家对自定义列控件有了大概的认识了。在以后的文章中,我们将看到更为复杂的自定义列控件的介绍。

  通过上篇文章的学习,相信大家都对简单的自定义列控件比较熟悉了,在本节中将创建较为复杂的列控件,现在让我们开始吧。

  相信大家肯定看到过这种情况,在评论的时候一些恶意的词语都会被**屏蔽掉,本节我们就来创建一个这样的审查的列控件CensorColumn。

  在上篇文章的LimitColumn中,通过继承BoundColumn类,然后重写FormatDataValue方法,以达到格式字段内容的功能,本节的这个审查控件也可以通过这样的方法来做,如果大家感兴趣可以自己试试。在这里我们将采用另一种方法来作,通过继承DataGridColumn类来创建。

  大家都知道BoundColumn类是继承自DataGridColumn类的,而BoundColumn类提供了DataField属性来显示数据源的字段,这次的CensorColumn类既然继承自DataGridColumn类,那我们也要创建DataField的这样一个属性来显示字段内容。

  代码如下:

private string m_DataFiled;
public string DataField
{
get
{
return this.m_DataFiled;
}
set
{
this.m_DataFiled = value;
}
}

  光有属性还不够,无法把读取的数据源的字段显示出来,所以我们还需要把数据源的字段显示到Cell的Text上。这里我们就要用到TableCell的DataBinding事件。这个事件是当数据源绑定到控件上发生,就是说当数据源绑定到DataGrid上时激发TableCell的此事件。通过激发此事件,我们静态绑定数据源中指定的字段(通过刚才的DataField属性完成),就可以显示字段的内容了。

  另外我们再来提下静态绑定,大家肯定都熟悉以下的语句:

DataBinder.Eval(Container.DataItem, "FieldName")
  它是通过访问DataGridItem's DataItem属性来获取字段的内容,那我们怎样在自定义的事件方法中获得呢?首先我们从数据源中的单元格里获得DataGridItem:DataGridItem gridItem = cell.NamingContainer,然后通过获得的DataGridItem获得DataItem:Object dataItem = gridItem.DataItem;这样我们就可以静态绑定数据了,代码如下:

public override void InitializeCell(TableCell cell, int columnIndex, ListItemType itemType)
{
base.InitializeCell (cell, columnIndex, itemType);
if((itemType == ListItemType.AlternatingItem)||(itemType == ListItemType.SelectedItem)||(itemType == ListItemType.Item))
{
cell.DataBinding += new EventHandler(PerformDataBinding);
}
}

private void PerformDataBinding(object sender, System.EventArgs e)
{
TableCell cell = (TableCell)sender;
DataGridItem gridItem = (DataGridItem)cell.NamingContainer;
Object dataItem = gridItem.DataItem;

if(!this.m_DataFiled.Equals(string.Empty))
{
cell.Text = (string)DataBinder.Eval(dataItem, DataField);
}
}

  接下来我们要做的就是根据要限制的字符来过滤内容了,代码如下:

//检查文本
private string m_CensorText;
public string CensorText
{
get
{
return this.m_CensorText;
}
set
{
this.m_CensorText = value;
}
}

//替换文本
private string m_CensoredText = "***";
public string CensoredText
{
get
{
return this.m_CensoredText;
}
set
{
this.m_CensoredText = value;
}
}
private string PerformShip(string text)
{ if(m_CensorText.Equals(string.Empty))
{
return text;
}
else
{
return text.Replace(this.m_CensorText,this.m_CensoredText);
}
}

  最后的完成代码为:

public class CensorColumn :DataGridColumn
{
private string m_DataFiled;
public string DataField
{
get
{
return this.m_DataFiled;
}
set
{
this.m_DataFiled = value;
}
}

//检查文本
private string m_CensorText;
public string CensorText
{
get
{
return this.m_CensorText;
}
set
{
this.m_CensorText = value;
}
}

//替换文本
private string m_CensoredText = "***";
public string CensoredText
{
get
{
return this.m_CensoredText;
}
set
{
this.m_CensoredText = value;
}
}

  public override void InitializeCell(TableCell cell, int columnIndex, ListItemType itemType)
{
base.InitializeCell (cell, columnIndex, itemType);
if((itemType == ListItemType.AlternatingItem)||(itemType == ListItemType.SelectedItem)||(itemType == ListItemType.Item))
{
cell.DataBinding += new EventHandler(PerformDataBinding);
}
}

private void PerformDataBinding(object sender, System.EventArgs e)
{
TableCell cell = (TableCell)sender;
DataGridItem gridItem = (DataGridItem)cell.NamingContainer;
Object dataItem = gridItem.DataItem;

if(!this.m_DataFiled.Equals(string.Empty))
{
cell.Text = PerformShip((string)DataBinder.Eval(dataItem, DataField));
}
}

private string PerformShip(string text)
{
if(m_CensorText.Equals(string.Empty))
{
return text;
}
else
{
return text.Replace(this.m_CensorText,this.m_CensoredText);
}
}

}

  在DataGrid中加入列控件:

<Columns>
  <custcols:CensorColumn CensorText="wit" DataField="ShipCountry"></custcols:CensorColumn>
</Columns>

  效果图:


  通过本节大家对于自定义控件肯定有了更进一步的了解,在下一篇中我们将扩展本节的审查列控件,以达到多个单词的验证功能。

  通过前面两篇文章的学习,大家对自定义列控件的基本知识都掌握了,本节为大家巩固下前面学习的东西,以上篇文章为基础,扩展审查列控件,使它能审查多个单词。

  我们通过把要检查的单词和替换的单词保存在XML文件中,这样便于修改。

  XML文件如下(Text.xml):

<?xml version="1.0" encoding="utf-8" ?>
<censors>
<censor>
<find>wit</find>
<replace>w*t</replace>
</censor>
<censor>
<find>ra</find>
<replace>*a</replace>
</censor>
</censors>

  完整代码如下:

public class CensorColumn :DataGridColumn
{
private string m_DataFiled;
public string DataField
{
get
{
return this.m_DataFiled;
}
set
{
this.m_DataFiled = value;
}
}

//检查文本
private string m_XmlFile;
public string XmlFile
{
get
{
return this.m_XmlFile;
}
set
{
this.m_XmlFile = value;
}
}

public override void InitializeCell(TableCell cell, int columnIndex, ListItemType itemType)
{
base.InitializeCell (cell, columnIndex, itemType);
if((itemType == ListItemType.AlternatingItem)||(itemType == ListItemType.SelectedItem)||(itemType == ListItemType.Item))
{
cell.DataBinding += new EventHandler(PerformDataBinding);
}
}

private void PerformDataBinding(object sender, System.EventArgs e)
{
TableCell cell = (TableCell)sender;
DataGridItem gridItem = (DataGridItem)cell.NamingContainer;
Object dataItem = gridItem.DataItem;

if(!this.m_DataFiled.Equals(string.Empty))
{
cell.Text = PerformShip((string)DataBinder.Eval(dataItem, DataField));
}
}

private string PerformShip(string text)
{
if(m_XmlFile.Equals(string.Empty))
{
return text;
}
else
{
return PerformXml(text);
}
}

private string PerformXml(string text)
{
string file = HttpContext.Current.Server.MapPath(this.XmlFile);
if(!File.Exists(file))
{
return text;
}
else
{
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(file);
XmlNode node = doc.DocumentElement;
XmlNodeList findNodes = node.SelectNodes("/censors/censor/find");
XmlNodeList replaceNodes = node.SelectNodes("/censors/censor/replace");
int i;
for(i=0;i<findNodes.Count;i++)
{
text = text.Replace(findNodes.Item(i).InnerText,replaceNodes.Item(i).InnerText);
}
return text;
}
}

}

  在DataGrid中添加列控件:

<Columns>
<custcols:CensorColumn XmlFile="Text.xml" DataField="ShipCountry"></custcols:CensorColumn>
</Columns>

效果图:


  一口气写完了三篇,相信大家看完后掌握了自定义列控件开发的基本知识。

  全选和多选的功能在DataGrid中使用的时候很多,以前我们都是创建CheckBox模板列,然后在后台中捕获ChecnkBox的选择情况来实现全选或多选.现在为了加快开发的速度,使用这个CheckBoxColumn列控件,可以很方便的实现多选或全选的功能.

  代码如下:

CheckBoxColumn
public class CheckBoxColumn : DataGridColumn
{
private String _strId=String.Empty;

public CheckBoxColumn(): base()
{
}

public override void InitializeCell(TableCell cell, int columnIndex, ListItemType itemType)
{

//重写父类InitializeCell方法
base.InitializeCell(cell, columnIndex, itemType);

//加入多选框
if(itemType == ListItemType.EditItem || itemType == ListItemType.Item || itemType == ListItemType.AlternatingItem || itemType == ListItemType.SelectedItem)
{

HtmlInputCheckBox checkbox = new HtmlInputCheckBox();
//可以自定义ID
if(_strId==String.Empty)
{
checkbox.Name = "checkboxCol";
checkbox.ID = "checkboxCol";
}
else
{
checkbox.Name = myID;
checkbox.ID=myID;
}

cell.Controls.Add(checkbox);

}

}

private String CreateName()
{
Random rnd=new Random(0);
String _strNameValue=Convert.ToString((int)rnd.Next(100));
return _strNameValue;
}

private String myID
{
get
{
return _strId;
}
}

public String ID
{

set
{
_strId=value;
}
}

public override string HeaderText
{
get
{
return base.HeaderText;
}
set
{
base.HeaderText = value;
}
}
public override TableItemStyle HeaderStyle
{
get
{
TableItemStyle t=new TableItemStyle();
t.HorizontalAlign=HorizontalAlign.Center;
return t;
}
}

//获得选中的Index值
public Int32[] SelectedIndexes
{
get
{

ArrayList selectedIndexList = new ArrayList();
//获得DataGrid中的选择框
foreach( DataGridItem item in this.Owner.Items )
{
HtmlInputCheckBox chkBox=null;
if(_strId==String.Empty)
{
chkBox = (HtmlInputCheckBox) item.FindControl("checkboxCol");
}
else
{
chkBox = (HtmlInputCheckBox) item.FindControl(myID);
}

//如果选中,就把选中的Index值放入ArrayList中
if ( chkBox != null && chkBox.Checked )
{
selectedIndexList.Add( item.ItemIndex );
}

}
return (Int32[])selectedIndexList.ToArray(typeof( System.Int32 ) );
}

}

//获得未选中的Index值
public Int32[] UnSelectIndexes
{
get
{
ArrayList UnSelectIndexList=new ArrayList();
foreach(DataGridItem item in this.Owner.Items)
{
HtmlInputCheckBox chkBox=null;
if(_strId==String.Empty)
{
chkBox=(HtmlInputCheckBox)item.FindControl("checkboxCol");
}
else
{
chkBox=(HtmlInputCheckBox)item.FindControl(myID);
}
//If it's not selected then add it to the arraylist
if(chkBox!=null&&chkBox.Checked==false)
{
UnSelectIndexList.Add(item.ItemIndex);
}
}
return (Int32[])UnSelectIndexList.ToArray(typeof(System.Int32));
}
}

//获得选中的DataKeys值
public object[] SelectedDataKeys
{
get
{
ArrayList dataKeyList = new ArrayList();
if(this.Owner.DataKeys.Count > 0)
{
foreach( Int32 selectedIndex in SelectedIndexes )
{
object DataKey = (this.Owner.DataKeys[selectedIndex].ToString());
dataKeyList.Add(DataKey);
}
}
return (object[])dataKeyList.ToArray(typeof( object ) );
}

}

//获得未选中的DataKeys值
public object[] UnSelectDataKeys
{
get
{
ArrayList UnSelDataKeyList=new ArrayList();
if(this.Owner.DataKeys.Count>0)
{
foreach(Int32 unSelectIndex in UnSelectIndexes)
{
object DataKey=(this.Owner.DataKeys[unSelectIndex].ToString());
UnSelDataKeyList.Add(DataKey);
}
}
return (object[])UnSelDataKeyList.ToArray(typeof(object));
}
}

}

  看过我前面几篇列控件介绍的朋友对上面的代码一定不会有什么问题.首先还是在DataGrid中引用这个列控件,方法和以前一样,这里就不多说了.然后看看具体的使用:

  获得选择行的Index值

CheckBoxColumn chkColumn = (CheckBoxColumn)this.DataGrid1.Columns[0];
foreach(object index in chkColumn.SelectIndexes)//SelectIndexes获得选择的Index值
{
Response.Write(index.ToString()+"<br>");
}

  获得选择行的DataKeys值

CheckBoxColumn chkColumn = (CheckBoxColumn)this.DataGrid1.Columns[0];
foreach(object index in chkColumn.SelectedDataKeys)//SelectedDataKeys获得选择的DataKeys值
{
Response.Write(index.ToString()+"<br>");
}

  获得未选择行的Index值和获得未选择行的DataKeys值

CheckBoxColumn chkColumn = (CheckBoxColumn)this.DataGrid1.Columns[0];
foreach(object index in chkColumn.UnSelectIndexes)
{
Response.Write(index.ToString()+"<br>");
}

CheckBoxColumn chkColumn = (CheckBoxColumn)this.DataGrid1.Columns[0];
foreach(object index in chkColumn.UnSelectedDataKeys)
{
Response.Write(index.ToString()+"<br>");
}

  全选/取消全选

foreach(DataGridItem item in this.DataGrid1.Items)
{
HtmlInputCheckBox chkBox=(HtmlInputCheckBox)item.FindControl("checkboxCol");
chkBox.Checked = true;
}
//如果你自定义了列控件的ID,"checkboxCol"换成自定义的ID值

  获得选择行的任意列的

CheckBoxColumn chkColumn = (CheckBoxColumn)this.DataGrid1.Columns[0];
foreach(object index in chkColumn.SelectIndexes)
{
Response.Write(DataGrid1.Items[(int)index].Cells[1].Text);
}

  基本的使用就介绍完了,都非常的简单.当然我们可以在这个列控件的基础上扩展新的功能,比如在Head加入全选/取消选择框

if(itemType == ListItemType.Header)
{
CheckBox headerCheckBox = new CheckBox();
headerCheckBox.ID = "chkAll";
headerCheckBox.CheckedChanged += new EventHandler(this.headerCheckBox_CheckedChanged);
headerCheckBox.AutoPostBack = true;
headerCheckBox.Text = "全选/取消";
cell.Controls.Add(headerCheckBox);
}

private void headerCheckBox_CheckedChanged(object sender, EventArgs e)
{
foreach (DataGridItem item in this.Owner.Items)
{
//iterate each DataGridItem and find our checkbox
HtmlInputCheckBox chkBox = (HtmlInputCheckBox) item.FindControl("checkboxCol");
//now set that checkboxCol value = to selected
if(chkBox.Checked == false)
chkBox.Checked = true;
else
chkBox.Checked = false;

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: