XTable扩展表服务器控件

分享于 

15分钟阅读

Web开发

  繁體

Sample Image - xtable.gif

介绍

某些时候,在打印时,我想在每页的顶部重复一个表头的情况。 为此,我需要在上使用 CSS <螺纹> 元素,但是由于我使用了 table,因为我不能使用 ASP.NET,因为,Table server控件不支持。 <螺纹> , <tbody><tfoot> 标签。

当我发现 Table 控件的部分是不可继承的(。RowCollectionCellCollection 类) 时,我决定不使用。 但是最近,我发现了一种方法,所以我决定构建这个控件。

我还会在一个 table 中运行一个精巧的方法来冻结top-和左头,并且很好地将这两个"升级"集成到标准的Table 控件。

因为我在ie环境中工作,所以我不关心 跨浏览器 兼容性。 但是,修改的额外标签没有CSS和没有脚本的脚本,所以它完全兼容 跨浏览器。

添加 <thead>,<tbody> 和 <tfoot> 标记

第一步是使用 roeder的 Lutz反射器来获取标准 Microsoft Table 服务器控件的代码的开放副本。 我把这个包括在源代码中作为 OpenTable

<螺纹> , <tbody><tfoot> 标签的共同点是它们是 table 行的分组( <tr> ),所以我扩展了微软的代码,在 TableTableRow 级别之间包含一个 RowGroup 级别。

例如 Table 类重写 CreateControlCollection,如下所示:

ProtectedOverridesFunction CreateControlCollection() As ControlCollection
 ReturnNew RowControlCollection(Me)EndFunction'CreateControlCollection

因此,XTable 类执行以下操作:

ProtectedOverridesFunction CreateControlCollection() As ControlCollection
 ReturnNew RowGroupControlCollection(Me)EndFunction'CreateControlCollection

TableRows 属性如下所示:

<Description("Table_Rows"), _
 PersistenceMode(PersistenceMode.InnerDefaultProperty), _
 MergableProperty(False)> _PublicOverridableReadOnlyProperty Rows() As TableRowCollection
 GetIfMe._rows IsNothingThenMe._rows = New TableRowCollection(Me)
 EndIfReturnMe._rows
 EndGetEndProperty'Rows

因此,XTableRowGroups 属性如下所示:

<Description("XTable_RowGroups"), _
 PersistenceMode(PersistenceMode.InnerDefaultProperty), _
 MergableProperty(False)> _PublicOverridableReadOnlyProperty RowGroups() As XTableRowGroupCollection
 GetIfMe._rowGroups IsNothingThenMe._rowGroups = New XTableRowGroupCollection(Me)
 EndIfReturnMe._rowGroups
 EndGetEndProperty'RowGroups

这种变化相当简单。 只有两个地方需要复杂的东西。 第一个是 Designer 中的GetDesignTimeHtml 替代。 这里也很简单,一旦理解了方法的逻辑,但添加额外的级别需要一些复杂性。 我不会在这里查看整个方法,但如果你比较 OpenTableXTable 中的代码,那么应该相当清楚。

另一个地方是 RowGroups 类的构造函数。 Rows 类的构造函数如下所示:

PublicSubNew()
 MyBase.New(HtmlTextWriterTag.Tr)EndSub'New

但是,在 XTable 中,RowGroups 可以呈现为 <螺纹> , <tbody> 或者 <tfoot> 因此我将它修改为默认值,允许呈现方法确定哪个标记真正呈现了。

为此,我向 XTable 添加了一些属性。 EnableTHead,如果设置为 True ,使第一个 RowGroup 呈现为 <螺纹> :

PublicProperty EnableTHead() AsBooleanGetReturnCType(Me.ViewState("EnableTHead"), Boolean)
 EndGetSet(ByVal Value AsBoolean)
 IfNot Value ThenMe.FreezeTop = FalseEndIfMe.ViewState("EnableTHead") = Value
 EndSetEndProperty'EnableTHead

EnableTFoot 属性对最后一个 RowGroup 执行相同的操作,尽管只有一个 RowGroupEnableTHeadEnableTFoot 都设置为 TrueRowGroup 将被呈现为 <螺纹>EnableTBodies 属性,默认为 True ,确定是否完全为 RowGroup 呈现任何标记。 如果将它设置为 False,则 <tbody> 渲染标记。

下面是 RenderStartTagRenderEndTag的代码:

PublicOverridesSub RenderBeginTag(ByVal writer As HtmlTextWriter)
 Me.AddAttributesToRender(writer)
 Dim _tag As HtmlTextWriterTag
 Dim _table As XTable = CType(Parent, XTable)
 If _table.EnableTHead AndMeIs _table.RowGroups(0) Then writer.RenderBeginTag(HtmlTextWriterTag.Thead)
 ElseIf _table.EnableTFoot AndNot _table.EnableTHead _
 AndMeIs _table.RowGroups(_table.RowGroups.Count - 1) Then writer.RenderBeginTag(HtmlTextWriterTag.Tfoot)
 ElseIf _table.EnableTFoot AndNot _table.RowGroups.Count <2 _
 AndMeIs _table.RowGroups(_table.RowGroups.Count - 1) Then writer.RenderBeginTag(HtmlTextWriterTag.Tfoot)
 ElseIf _table.EnableTBodies Then writer.RenderBeginTag(HtmlTextWriterTag.Tbody)
 EndIfEndSub'RenderBeginTag
PublicOverridesSub RenderEndTag(ByVal writer As HtmlTextWriter)
 Dim _table As XTable = CType(Parent, XTable)
 If _table.EnableTHead Or _table.EnableTBodies Or _table.EnableTFoot Then writer.RenderEndTag()
 EndIfEndSub'RenderEndTag

在伪代码中,它看起来像这样:

If <thead>s are enabled AND this rowgroup is the first one:
 Render as <thead>
Otherwise if <tfoot>s are enabled AND <thead>s 
 are not, AND this rowgroup is the last one:
 Render as <tfoot>
Otherwise if <tfoot>s are enabled AND there 
 are at least 2 rowgroups, AND this is the last one:
 Render as <tfoot>
Otherwise if <tbodies> are enabled:
 Render as <tbody>

如果至少启用了 RowGroup 标记类型之一,则只为 RowGroup 呈现结束标记。

我可以在这里停止,我会有一个可以用的Table 服务器控件,支持这三个附加标签。 它也是完全兼容的跨浏览器,因为我前面提到过,没有CSS和没有脚本涉及的脚本。 但我仍然想冻结头部。

冻结标题

我会遇到 Brett的例子of如何使用CSS表达式在 HTML table 中冻结标题。 他的示例使用样式表,但是我很关心使用样式表,因为我不能控制用户可以能使用的样式表。 我更喜欢使用 inline CSS。

首先,我创建了五个新属性:

  • OuterHeightOuterWidth<div> 它环绕着我们的桌子。
  • FreezeTop 是一个 布尔型 确定第一个 RowGroup 是否要冻结或者不被冻结。
  • FreezeLeft 是一个 整型 确定左侧要冻结的列数。
  • FreezeStyleTableItemStyle 继承,并确定冻结区域中任何单元格的样式。

原始 Table 控件重写 TableCell 中的AddAttributesToRender 以添加 ColspanRowspan 属性。 我更进一步:

ProtectedOverridesSub AddAttributesToRender(ByVal writer As HtmlTextWriter)
 '*********'Original Microsoft code'*********MyBase.AddAttributesToRender(writer)
 Dim i AsInteger = Me.ColumnSpan
 If i> 0Then writer.AddAttribute(HtmlTextWriterAttribute.Colspan, _
 i.ToString(NumberFormatInfo.InvariantInfo))
 EndIf i = Me.RowSpan
 If i> 0Then writer.AddAttribute(HtmlTextWriterAttribute.Rowspan, _
 i.ToString(NumberFormatInfo.InvariantInfo))
 EndIf'********* My added code
 '*********Dim _row As XTableRow = CType(Parent, XTableRow)
 Dim _rowgroup As XTableRowGroup = CType(Parent.Parent, XTableRowGroup)
 Dim _table As XTable = CType(Parent.Parent.Parent, XTable)
 Dim isFrozenTop AsBoolean = (_table.FreezeTop AndAlso _
 _table.EnableTHead AndAlso _rowgroup Is _table.RowGroups(0))
 Dim isFrozenLeft AsBoolean = (_table.FreezeLeft> 0 _
 AndAlso _row.Controls.IndexOf(Me) <_table.FreezeLeft)
 If isFrozenTop And isFrozenLeft Then writer.AddStyleAttribute("z-index", "30")
 writer.AddStyleAttribute("top", _
 "expression(parentNode.parentNode.parentNode.parentNode.scrollTop-2)")
 writer.AddStyleAttribute("left", _
 "expression(parentNode.parentNode.parentNode.parentNode.scrollLeft-2)")
 ElseIf isFrozenTop Then writer.AddStyleAttribute("z-index", "20")
 writer.AddStyleAttribute("top", _
 "expression(parentNode.parentNode.parentNode.parentNode.scrollTop-2)")
 ElseIf isFrozenLeft Then writer.AddStyleAttribute("z-index", "10")
 writer.AddStyleAttribute("left", _
 "expression(parentNode.parentNode.parentNode.parentNode.scrollLeft-2)")
 EndIfIf isFrozenTop Or isFrozenLeft Then writer.AddStyleAttribute("position", "relative")
 _table.FreezeStyle.AddAttributesToRender(writer)
 EndIfEndSub'AddAttributesToRender

在 postback 上保留滚动位置

如果每次页回发时使用这个新控件,table 将会回滚到原始位置,这将非常烦恼。 因此,我修改了目前不支持的微软 TabStrip 控件所使用的功能。 实际上,我在页面上创建了一个隐藏控件,并将一个 onscroll 事件添加到 <div> 标记,它将滚动位置写入隐藏控件。 如果垂直滚动被四个像素移动,并且水平滚动被像素移动,则典型值可能为 34: 50.

PrivateSub RegisterScript()
 Dim divID AsString = Me.ID + "_div"Dim _scrollPos() AsString = Me.HelperData.Split(":"c)
 Dim script AsString = "<script language="'javascript'" type='text/javascript'>" _ + ControlChars.CrLf _
 + "<!--" _
 + ControlChars.CrLf _
 + divID + ".scrollTop =" + _scrollPos(0) + ";" _
 + ControlChars.CrLf _
 + divID + ".scrollLeft =" + _scrollPos(1) + ";" _
 + ControlChars.CrLf _
 + "//-->" _
 + ControlChars.CrLf _
 + "</script>" Page.RegisterStartupScript(Me.ID, script)
 script = NothingEndSub'RegisterScript

这里方法将脚本写入页之前 </窗体> 页面上每个 XTable的标记。 它根据从隐藏控件返回的信息来设置 scrollTopscrollLeft 值。 现在通过 postback 保存滚动位置。 当然,只有在 OuterHeight 或者 OuterWidth 有值的情况下才调用这里方法。 如果这两个属性都是空的,则不包含 <div> 完全呈现,因为它不相关。

始终使用OptionExplicit和OptionStrict编译"

我了解到,如果不使用 OptionExplicitOptionStrict 进行编译,并且控件在这些设置中使用,控件很可以能崩溃。 我发布的代码示例是用以下两个选项编译的。

已知问题

因为 <选择> 标记是窗口控件,它最后呈现。 这意味着它的z-index 总是大于你分配给 table 单元格的那个。 这意味着当滚动时,下拉列表和列表框将传递到头部,而不是在。

我对这个问题所看到的唯一解决方案是:

  • 不使用 <选择> 在这些表格中
  • 使用一些脚本来渲染 <选择> 当它侵入冻结的细胞或者
  • 使用小图形小故障。

我个人来说,我将用( c )。


Server  控制  ext  tab    Extend  
相关文章