如何使用DataGrid控件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用DataGrid控件相关的知识,希望对你有一定的参考价值。
如何在控件中随时可以给某一行纪录的某一个字段加值呢?
〔DataGrid控件〕在三种控件当中,DataGrid是迄今为止功能最为丰富的,但也是最不灵活的控件。这种在输出html时不够灵活的特点是因为它最初就是被设计成以表格的形式输出数据。每一条记录输出时会建立一对<tr>标签,而每个字段的值输出时则建立一对<td>标签。
DataGrid含有几个属性可以提高其可用性。如,通过设置DataGrid的AllowSorting属性为true,并加入少量代码,DataGrid就具备了按不同字段排序的功能。此外,设定相关属性来实现分页以及单条记录编辑的功能更加增强了DataGrid的可用性。
除了在可用性方面的支持以外,DataGrid同时也相当节省开发时间。使用DataGrid在WEB页面上显示数据只需要两行代码。一行用来设定与DataGrid绑定的数据源(DataSource),另一条则用来执行绑定命令(DataBind())。当然,在Repeater中实现这样的功能并非不可能,只是,相比较使用DataGrid而言,你需要花费相当多的时间和精力来实现这些功能。
尽管DataGrid有这样那样令人印象深刻的优点,它的两个缺点也同样不能忽视。首先,如前所述,DataGrid在个性化输出数据方面功能有限。当然,你可以定制字体、颜色以及线条宽度等等,但它始终只能是HTML表格。
每个在DataGrid中的列都是DataGridColumn类的一个实例。有五种DataGrid列的形式:
·BoundColumn
·ButtonColumn
·EditColumn
·HyperLinkColumn
·TemplateColumn
每种类型都会以一种方式允许页面访问与DataGrid进行交互。例如,BoundColumn将DataSource的字段值显示为纯文本;而HyperLinkColumn则将之显示为一个超级链接。另外,开发者可以通过写一个继承自DataGridColumn的自定义类来定制DataGrid列的样式。
尽管DataGrid具有这么多的增强可用性的属性,却仍然显得死板而不够灵活。这是因为,不论什么样的属性,都需要对DataGrid所生成的表格进行相关的设置而生效。这无疑会使表格变得臃肿而失去灵活性。例如,DataGridColumn的设置会对表格的每一行的相应列生效。DataGrid的这种局限性阻碍了更有创意地显示数据。比如,你希望每五条记录被显示在一行,或根本不想要表格来显示数据,你将不得不放弃使用DataGrid。
DataGrid的第二个缺陷是它的性能。在三种数据控件中,DataGrid是相对性能最差的。由DataGrid所生成的ViewState将会相当庞大,特别是在DataGrid含有较多的行时。当然,你也可以关闭ViewState功能,但代价是你将不能使用排序、分页以及记录编辑等功能。
为了测量DataGrid的性能,我使用了微软的Web Application Stress Tool (WAST)。精确的测试条件设定以及测试用代码将会在本文的结尾给出。
WAST将会对WEB服务器发出对一个特定URL的请求。每个测试将会针对一个URL在一分钟之内连续不断地请求。WAST将会一个代表性能的数值,代表WEB服务器将会在一秒钟内执行ASP.Net页面多少次。
两个测试将显示一个仅仅显示数据的DataGrid。DataGrid将会显示Northwinds数据库中的Customers表的4个字段的内容(总计91条记录)。DataGrid的AutoGenerateColumns属性将会被设为True。第一个测试将DataGrid置于一个Form中,第二个则不置于Form中。将控件置于Form中而不指定其EnableViewState为False,则控件将会一直使用ViewState来维持其状态。对ViewState的设定是为了有一个耗时的处理过程,来看一下它对于每秒种的页面请求有什么样的影响。测试结果见图1。
图1:对DataGrid的每秒请求次数
在下面我们要讨论并测试的DataList和Repeater中,我们会看到它们的性能将优于DataGrid。
〔DataList控件〕
如前所述,DataGrid使用表格来显示数据。你也许需要更进一步地控制数据的显示。例如,你想使数据在表格中显示,但不是每行只有一条记录,而是多条。又或者,你并不想使用表格来显示数据,而是只将它们显示在一系列<span>标签中。
DataList放弃了DataGrid中列表显示数据的概念,而是使用事先定义好的模板(Template)来定制显示。通过使用模板,可以同时使用HTML标签或数据绑定。这里的数据绑定的形式为:<%# … %>,用来显示数据源中给定条目的数据记录。如下的ItemTemplate将会显示数据源中CompanyName字段:
<asp:DataList runat="server" id="myDataList">
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "CompanyName") %>
</ItemTemplate>
</asp:DataList>
通过修改上面的模板,我们可以使CompanyName字段显示为粗体字,而ContactName字段则以正常式样显示在CompanyName之下。
<asp:DataList runat="server" id="myDataList">
<ItemTemplate>
<b><%# DataBinder.Eval(Container.DataItem, "CompanyName") %></b>
<br />
<%# DataBinder.Eval(Container.DataItem, "ContactName") %>
</ItemTemplate>
</asp:DataList>
对于DataList数据源中的每一条记录,ItemTemplate会通过定义HTML标签来以相同的样式显示数据。ItemTemplate还支持其它其它6种模板:
·AlternatingItemTemplate
·EditItemTemplate
·FooterTemplate
·HeaderTemplate
·ItemTemplate
·SelectedItemTemplate
·SeparatorTemplate
默认情况下DataList会将记录显示在HTML表格中。然而,通过设定RepeatColumn属性,你可以设置在一行中显示多少条记录。更进一步,你甚至可以指定DatList的内容不显示在表格中,而是<span>标签中。这可以通过设定RepearLayout属性来实现。
通过模板、RepeatColumn和RepeatLayout属性,很明显DataList在定制数据输出样式方面较DataGrid更具灵活性,使得用户界面设计可以更加友好。当然,我们还需要进行功能性的对比,如分页、排序、记录编辑等等。
通过EditItemIndex模板和EditCommand,UpdateCommand以及CancelCommand事件,DataList将支持记录编辑的功能。不过,比较DataGrid而言,这需要耗费更多的开发时间来实现。这种开发时间上的不一致主要有两个原因:
·编辑/更新/删除按钮在DataGrid中可以通过设定EditCommandColumn来自动添加;而在DataList中则需要手动添加。
·DataGrid的BoundColumn列样式自动使用文本框控件来显示记录编辑界面。而在DataList中,你必须通过EditItemTemplate明确地指定使用什么样的编辑界面。
实现DataList中的分页、排序功能同记录编辑功能情况一样,并不算非常复杂。这些功能可以通过巧妙的编程加以实现,只是耗费一些开发时间。所以,如果需要用户对数据记录进行排序或编辑的话,使用DataGrid要比使用DataList方便得多。
DataList的性能要比DataGrid好一些,特别是当DataList被包含在Form当中时。图2显示了WAST对DataList的测试。
图2:对DataList的每秒请求次数
可以看出,在被Web Form包含的情况下,DataList的性能要明显好于DataGrid。
〔Repeater控件〕
Repeater控件是三种数据控件中在HTML输出方面最为灵活的控件。Repeater会按照你所要求的样式严格地输出数据记录。所以,如果你不想以表格方式或者简单的<span>输出数据,那么最好使用Repeater。
与DataList一样,Repeater使用模板来指定输出样式。Repeater支持如下五种模板:
·AlternatingItemTemplate
·FooterTemplate
·HeaderTemplate
·ItemTemplate
·SeparatorTemplate
HederTemplate和FooterTemplate指定在真正的记录输出之前或之后应处理的HTML内容。AlternatingItemTemplate和ItemTemplate则指定实际的每条输出记录的HTML样式。如,你需要绑定一个包含雇员信息的DataSet到一个Repeater,字段名为EmployeeName。如果你想在页面中不排序地显示这些记录,你可以使用如下的语句:
<asp:Repeater runat="server" id="rptEmployees">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# DataBinder.Eval(Container.DataItem, "EmployeeName") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
Repeater类不是继承自WebControl类的,这一点与DataGrid和DataList不同。所以,Repeater没有样式方面的属性可供设定。也就是说,如果你想格式化输出Repeater的数据记录,你必须使用HTML标签来设定样式。如,在一例中,如果我们想将雇员名字显示成粗体,我们必须在ItemTemplate设置相应的HTML标签:
<ItemTemplate>
<li><b><%# DataBinder.Eval(Container.DataItem, "EmployeeName")%></b></li>
</ItemTemplate>
而如果使用DataGrid或DataList,我们只通过设定ItemStyle-Font-Bold属性为True即可实现。
Repeater在格式化设定上的欠缺,直接反映到开发时间的延长上来。对输出数据样式上的越多要求,就越会导致开发周期的延长。这些在模板中规定样式的HTML标签也越发得显得混乱,而且,在将来页面更改时会更加困难,特别是当一个新的开发人员接替工作时。而使用DataGrid或DataList你尽可以只设定样式属性,而不使用模板。而且,如果使用Visual Studio.Net或ASP.Net Web Matrix工作时,这些属性更可以被直接设定而无需编码。
因为Repeater开发时间的延长,其在内建功能(分页、排序及编辑)上的支持也显得不足。因此在可用性方面,Repeater有着明显的缺陷。当然,<b>如果</b>用户对于如何显示数据无所谓的话,这也算不了什么大问题。我之所以强调这个“如果”,是因为尽管用户有时在设计时并不要求能够分页、排序或编辑记录,但这样的要求往往会在开发后期,或在他们能看到显示出来的记录后产生。
Repeater唯一优于DataGrid和DataList的特点是它的性能,尤其明显优于DataGrid。而比DataList略高一点点。
〔结论〕
在ASP.Net页面上显示数据时,多数的程序员会选择他们所熟悉的控件来使用,特别是DataGrid。然而,这样盲目的选择在没有“最好的通用控件”的情况下是不明智的。在选择控件来显示数据前,不妨问自己几个问题来帮助决策:是否允许用户对记录排序?是不是记录需要显示在非表格的情况下?页面是否会被高频度地访问,因此应多考虑性能?
DataGrid提供了最多的功能,如允许访问者对记录编辑、排序或分页。同时它也是最容易使用的,甚至于简单到只需要将之添加到页面中而不必额外编写代码。不过这些易用性是以性能的损失为代价的。DataGrid在三种控件中是效率最低的,特别是在使用Web Form的情况下。
通过使用模板,DataList提供了比DataGrid更加优秀的界面效果。不过这需要以牺牲一定的开发时间为代价。为了添加排序、分页和编辑功能,程序员不得不花费比使用DataGrid更多的精力来进行编码,虽然它的性能要优于DataGrid。
最后,Repeater允许对数据记录作最大限度的HTML定制。通常,使用Repeater来显示数据记录比使用DataGrid和DataList要耗费更长的开发时间。另外,它不支持内建的编辑、排序和分页功能。所幸的是,Repeater在性能上要优于其它两种控件,特别是明显优于DataGrid。 参考技术A DataGrid控件不是数据容器
所以你不能够在DataGrid控件中更改数据
只能相应的更改数据源如DataTable
如何将 Colgroup 标记添加到 ASP:Datagrid 控件?
【中文标题】如何将 Colgroup 标记添加到 ASP:Datagrid 控件?【英文标题】:How Do I Add Colgroup Tag to ASP:Datagrid Control? 【发布时间】:2011-03-09 19:28:55 【问题描述】:如何将 colgroup 标签添加到 datagrid 控件,以便我可以使用 css 设置每一列的样式?
【问题讨论】:
什么版本的 ASP.NET? 【参考方案1】:我认为这已在 .NET 3.5 中得到解决,但我找不到任何参考资料。无论如何,这是一个手动服务器控件,允许您指定 colgroup
...
public class ColGroupGridView : GridView
private ColGroup _ColGroup = null;
private ITemplate _ColGroupTemplate = null;
[TemplateContainer(typeof(ColGroup))]
public virtual ITemplate ColGroupTemplate
get return _ColGroupTemplate;
set _ColGroupTemplate = value;
protected override void CreateChildControls()
base.CreateChildControls();
_ColGroup = new ColGroup();
ColGroupTemplate.InstantiateIn(_ColGroup);
protected override void Render(HtmlTextWriter writer)
// Get the base class's output
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
base.Render(htw);
string output = sw.ToString();
htw.Close();
sw.Close();
// Insert a <COLGROUP> element into the output
int pos = output.IndexOf("<tr");
if (pos != -1 && _ColGroup != null)
sw = new StringWriter();
htw = new HtmlTextWriter(sw);
_ColGroup.RenderPrivate(htw);
output = output.Insert(pos, sw.ToString());
htw.Close();
sw.Close();
// Output the modified markup
writer.Write(output);
internal class ColGroup : WebControl, INamingContainer
internal void RenderPrivate(HtmlTextWriter writer)
writer.Write("<colgroup>");
base.RenderContents(writer);
writer.Write("</colgroup>");
像这样使用它...
<custom:ColGroupGridView ... runat="server">
<ColGroupTemplate>
<col class="itemid" />
<col class="cover-image" />
<col class="title" />
<col class="number" />
<col class="year" />
<col class="rating" />
<col class="cgc-rating" />
<col class="description" />
</ColGroupTemplate>
<!-- Rest of stuff here... -->
</custom:ColGroupGridView>
来源:Jeff Prosise's Blog
【讨论】:
如何以编程方式添加 col?例如,我想做一些类似 ColGroupGridView.ColGroup.Add(col) 或类似的事情 当然。为 _ColGroup 变量创建公共获取/设置。那么你应该可以像这样添加...Dim Col As New HtmlGenericControl("COL") Col.Attributes.Add("class", "myCssClass") ColGroupGridView.ColGroup.Add(Col)
你能解释一下 ColGroupTemplate 是什么以及我应该如何初始化它吗?到目前为止,我有这个 public void AddCol(string colClass) HtmlGenericControl col = new HtmlGenericControl("COL"); col.Attributes.Add("class", colClass); _ColGroup = 新 ColGroup(); _ColGroup.Controls.Add(col); ColGroupTemplate.InstantiateIn(_ColGroup);最后一行给了我一个未设置为对象实例的对象引用,因为 ColGroupTemplate 为空。
@Arizona1911 不要担心模板,它允许您通过标记来控制它。您需要将 _ColGroup 变量公开。这本质上是<colgroup>
标签,它继承了 Control 允许您在其中嵌入其他控件。您可以使用前面提到的 sn-p 将<col>
添加到组中。
谢谢!这将是扩展 gridview 的更有效方式。【参考方案2】:
为了动态添加列,做一个小改动怎么样?
/// <summary>
/// Represents a Col element.
/// </summary>
public class HtmlCol : HtmlGenericControl
/// <summary>
/// Default constructor.
/// </summary>
public HtmlCol()
: base("col")
/// <summary>
/// Collection of HtmlCols
/// </summary>
public class HtmlCols : List<HtmlCol>
/// <summary>
/// Default constructor.
/// </summary>
public HtmlCols()
/// <summary>
/// Adds a col to the collection.
/// </summary>
/// <returns></returns>
public HtmlCol Add()
var c = new HtmlCol();
base.Add(c);
return c;
/// <summary>
/// Represents a colgrpup tag element.
/// </summary>
internal class ColGroup : WebControl, INamingContainer
internal void RenderPrivate(HtmlTextWriter writer)
writer.Write("<colgroup>");
base.RenderContents(writer);
writer.Write("</colgroup>");
internal void RenderPrivate(HtmlTextWriter writer, HtmlCols cols)
writer.Write("<colgroup>");
base.RenderContents(writer);
foreach (var c in cols)
c.RenderControl(writer);
writer.Write("</colgroup>");
[ToolboxData("<0:PlainGrid runat=server></0:Table>")]
public class PlainGrid : GridView
private ColGroup _colGroup = null;
private ITemplate _colGroupTemplate = null;
private HtmlCols _cols = null;
[TemplateContainer(typeof(ColGroup))]
public virtual ITemplate ColGroupTemplate
get return _colGroupTemplate;
set _colGroupTemplate = value;
protected override void CreateChildControls()
base.CreateChildControls();
if (ColGroupTemplate != null)
ColGroupTemplate.InstantiateIn(_colGroup);
protected override void Render(HtmlTextWriter writer)
// Get the base class's output
var sw = new StringWriter();
var htw = new HtmlTextWriter(sw);
base.Render(htw);
string output = sw.ToString();
htw.Close();
sw.Close();
// Insert a <COLGROUP> element into the output
int pos = output.IndexOf("<tr");
if (pos != -1 && _colGroup != null)
sw = new StringWriter();
htw = new HtmlTextWriter(sw);
_colGroup.RenderPrivate(htw, _cols);
output = output.Insert(pos, sw.ToString());
htw.Close();
sw.Close();
// Output the modified markup
writer.Write(output);
/// <summary>
/// Gets/Sets col items.
/// </summary>
public HtmlCols Cols
get return _cols;
set _cols = value;
/// <summary>
/// Default constructor
/// </summary>
public PlainGrid()
base.AutoGenerateColumns = false;
_colGroup = new ColGroup();
_cols = new HtmlCols();
【讨论】:
【参考方案3】:我已经搜索了几天来寻找有关如何将 ColGroup 模板添加到 GridView 的解决方案。使用 Josh uphere 给出的答案,以及几天阅读派生对象,尤其是 GridView,我认为更新且有效的解决方案可以帮助周围的人。
Imports System.ComponentModel
Imports System.Web.UI
Imports Microsoft.VisualBasic
Imports System.IO
Namespace CustomControls
<ToolboxData("<0:GridViewColGroup runat=server></0:GridViewColGroup>")> _
<System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust"), _
ParseChildren(True)> _
Public Class GridViewColGroup
Inherits GridView
Implements INamingContainer
Private _ColGroup As ColGroup = Nothing
Private _ColGroupTemplate As ITemplate = Nothing
<Browsable(False), _
Description("The ColGroup template."), _
TemplateContainer(GetType(ColGroup)), _
PersistenceMode(PersistenceMode.InnerProperty)> _
Public Overridable Property ColGroupTemplate() As ITemplate
Get
Return _ColGroupTemplate
End Get
Set(ByVal value As ITemplate)
_ColGroupTemplate = value
End Set
End Property
<Browsable(False), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
Public Property ColGroup() As ColGroup
Get
Me.EnsureChildControls()
Return _ColGroup
End Get
Set(ByVal value As ColGroup)
_ColGroup = value
End Set
End Property
Protected Overrides Sub CreateChildControls()
MyBase.CreateChildControls()
_ColGroup = New ColGroup()
If Not ColGroupTemplate Is Nothing Then
ColGroupTemplate.InstantiateIn(_ColGroup)
End If
Me.Controls.Add(_ColGroup)
End Sub
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
EnsureChildControls()
' Get the base class's output
Dim sw As New StringWriter()
Dim htw As New HtmlTextWriter(sw)
MyBase.Render(htw)
Dim output As String = sw.ToString()
htw.Close()
sw.Close()
' Insert a <COLGROUP> element into the output
Dim pos As Integer = output.IndexOf("<tr")
If pos <> -1 AndAlso _ColGroup IsNot Nothing Then
sw = New StringWriter()
htw = New HtmlTextWriter(sw)
_ColGroup.RenderPrivate(htw)
output = output.Insert(pos, sw.ToString())
htw.Close()
sw.Close()
End If
' Output the modified markup
writer.Write(output)
End Sub
End Class
<ToolboxItem(False)> _
Public Class ColGroup
Inherits WebControl
Implements INamingContainer
Friend Sub RenderPrivate(ByVal writer As HtmlTextWriter)
writer.Write("<colgroup>")
MyBase.RenderContents(writer)
writer.Write("</colgroup>")
End Sub
End Class
End Namespace
这确实为您提供了像 Josh sais 一样使用它的机会:
<aspcust:GridViewColGroup runat="server" ID="gridName">
<ColGroupTemplate>
<col class="some_class_1" />
<col class="some_class_2" />
...
<col class="some_class_n" />
</ColGroupTemplate>
<Columns>
...
</Columns>
</aspcust:GridViewColGroup>
如果将派生类包装到命名空间中,并在 web.config 中注册如下:
<configuration>
<system.web>
<pages>
<controls>
<add tagPrefix="aspcust" namespace="CustomControls" />
</controls >
</pages >
</system.web>
</configuration>
以编程方式,您可以在 ColGroup 中添加一个新列,例如 PreRender:
Protected Sub gridName_PreRender(ByVal sender As Object, ByVal e As System.EventArgs)
Dim grd As CustomControls.GridViewColGroup = sender
Dim wctrl As New WebControl(HtmlTextWriterTag.Col)
wctrl.CssClass = "some_class_m"
grd.ColGroup.Controls.Add(wctrl)
End Sub
干杯。
【讨论】:
以上是关于如何使用DataGrid控件的主要内容,如果未能解决你的问题,请参考以下文章
vb DataGrid控件 如何加一列CheckBox控件?
如何从头开始创建一个快速的 WPF Datagrid 控件?
如何访问 DataGrid.RowDetailsTemplate 中的控件?