在 .Net 3.5 的 Gridview 中仅显示用于插入新行的页脚
Show only the footer for inserting new row in Gridview in .Net 3.5
当我的 Gridview 与 "few rows" 数据绑定时,我当前添加新行的方法是一种适当的设计并且有效 "well"。但是,如果与 "many rows" 数据绑定,我当前添加新行的方法存在缺陷:我正在使用的 EmptyDataTemplate 使用 FooterTemplate[ 公开=39=].因此,如果我有 3 行数据并单击 "Add New Record",网格将重新显示,第 4 行全部 "prepared" 用于数据输入。然而,如果我有 30 行,要插入的行的显示太低,需要滚动。
Protected Sub AddNewRecord(ByVal sender As Object, ByVal e As EventArgs)
GridView1.ShowFooter = True
'rebind data so GridView1_RowDataBound gets a chance to populate the footer
iSubscriberID = Session("SubscriberID")
LoadDataGrid(iSubscriberID)
End Sub
我希望能够改进添加新行的操作,但仍然使用 FooterTemplate。
是否有任何代码可以添加到我的 GridView1_RowDataBound 处理程序中以隐藏现有数据行但仍公开 EmptyDataTemplate 以便通过 FooterTemplate 插入?我试过在那里破解一些东西但没有成功。这是该处理程序的现有代码:
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) _
Handles GridView1.RowDataBound
'-------------------------------------------------------------------------------------------*
' Handle 'Insert' requirements:
' - Bind dropdownlist controls with the possible incumbents and backups for some new position
'-------------------------------------------------------------------------------------------*
If e.Row.RowType = DataControlRowType.Footer Then
' Finding the Dropdown control.
Dim ctrl As Control = e.Row.FindControl("ddlUsers")
If ctrl IsNot Nothing Then
Dim dd As DropDownList = TryCast(ctrl, DropDownList)
dd.DataSource = allUsers
dd.DataBind()
End If
Dim ctrlB As Control = e.Row.FindControl("ddlUsersBackup")
If ctrlB IsNot Nothing Then
Dim ddB As DropDownList = TryCast(ctrlB, DropDownList)
ddB.DataSource = allUsers
ddB.DataBind()
End If
End If
End Sub
我正在为所有列使用 TemplateField 定义;这是一个示例,显示了 FooterTemplate:
的一部分
<asp:TemplateField HeaderText="Incumbent">
<ItemTemplate>
<asp:Label ID="lblUser" runat="server" Text='<%# Eval("Incumbent")%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="lblUser" runat="server" Text='<%# Eval("Incumbent")%>' Visible = "false"></asp:Label>
<asp:DropDownList Width="100%" runat="server"
id="ddlUsers" AutoPostBack="true"
DataTextField="FullName" DataValueField="UserID"
OnSelectedIndexChanged="ddlUsers_SelectedIndexChanged">
</asp:DropDownList>
</EditItemTemplate>
<FooterTemplate>
<asp:Label ID="lblUser" runat="server" Text='Set Incumbent'></asp:Label>
<br />
<asp:DropDownList Width="100%" runat="server"
id="ddlUsers" AutoPostBack="true"
DataTextField="FullName" DataValueField="UserID"
OnSelectedIndexChanged="ddlUsers_SelectedIndexChanged">
</asp:DropDownList>
</FooterTemplate>
</asp:TemplateField>
我的另一个可能可行的想法是将页面滚动到底部,以便在使用 ShowFooter=True 重新填充 gridview 时,"insertion" 行始终可见。但是,这似乎涉及一些 Javascript 我希望在此页面上避免的内容。
编辑:2016 年 2 月 18 日 - 尝试将分页添加到 Gridview - 一个新的并发症
@Lesmian - 按照您的建议添加寻呼机很容易,但现在它完全破坏了 Gridview:
我研究了那个错误,但我不明白为什么我的职位强类型集合不支持分页;这是为 Gridview 实例化我的数据源的代码:
Public Class Positions
Implements IEnumerable(Of Position)
Public List As New List(Of Position)
Public Function GetEnumerator() As IEnumerator(Of Position) _
Implements IEnumerable(Of Position).GetEnumerator
Return List.GetEnumerator()
End Function
Private Function GetEnumerator1() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return List.GetEnumerator()
End Function
Public Sub New(ByVal subscriberID As Integer, Optional ByVal filterOnUserID As Integer = 0)
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
Try
cmd = New SqlCommand("dbo.GetPositionsBySubscriberID", connection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@SubscriberID", subscriberID)
cmd.Parameters.AddWithValue("@UserID", filterOnUserID) 'non-zero UserID returns only positions where User is Incumbent or Backup
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
Dim p As Position = New Position(objReader)
List.Add(p)
Loop
objReader.Close()
connection.Close()
解决原问题的加分页器的方法又开辟了一个新的问题。有什么想法吗?
滚动 gridview 需要 javascript,但如果您不想使用它,也许其他方法也适合您的需要。如果您将寻呼机添加到您的 gridview 并在每页中设置少量项目,那么添加新项目将不会导致滚动条出现。然而,使用这种方法我们还有其他缺陷 - 新项目可能会出现在新页面上,因此您应该强制网格显示最后一页,然后新行将始终可见:
Protected Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) _
Handles GridView1.RowCommand
' Insert data if the CommandName == "Insert"
' and the validation controls indicate valid data...
If e.CommandName = "Insert" AndAlso Page.IsValid Then
' Insert new record
GridView1DataSource.Insert()
' Indicate that the user needs to be sent to the last page
SendUserToLastPage = True
End If
End Sub
Protected Sub GridView1_DataBound(sender As Object, e As EventArgs) _
Handles GridView1.DataBound
' Send user to last page of data, if needed
If SendUserToLastPage Then
GridView1.PageIndex = GridView1.PageCount - 1
End If
End Sub
您可以在此处找到此方法的完整示例:http://www.asp.net/web-forms/overview/data-access/enhancing-the-gridview/inserting-a-new-record-from-the-gridview-s-footer-vb
编辑:2016 年 2 月 18 日 - 数据源不支持服务器端数据分页错误
您的自定义集合必须实现 ICollection 接口才能使用 GridView 服务器端分页。 IEnumerable 没有实现 ICollection,这就是您出错的原因。有关 vb 中的实施示例,您可以阅读:https://support.microsoft.com/en-us/kb/306961 and this: http://www.codeproject.com/Articles/265692/Having-fun-with-custom-collections。之后 GridView 应该为您完成剩下的工作。
总体思路:
1. 将您的 GridView 置于固定高度的可滚动 div
2. 在 div 下方放置单行 table 以及您需要插入新记录和 "Add" 按钮
的所有控件
3. 如果可能,使用 SqlDataSource 填充 GridView 并将插入命令包含到 SqlDataSource
4. 在 InsertParameters 块中使用 asp:controlParameter 绑定到新值。
5. 将代码添加到 Add_Click 处理程序
mySqlDataSource.Insert()
PS:更好的是,将您的 GridView 重写为 ListView(.NET 3.5 支持)。这会给你更多的灵活性。例如,您可以将插入放在第一行。
OP 中的实际问题似乎在 post 返回后归结为 "How do I keep the row for inserting in view"。
Page
对象已经有一个名为 Focus
的方法,可用于在页面呈现完成后使特定控件获得焦点。
当位于浏览器可见区域之外的控件获得焦点时,浏览器会将该控件滚动到视图中,以便用户可以看到焦点所在的内容。
因此,要使插入行可见,只需确保在后面的代码中使其可见时将焦点设置在行中合适的控件上。
当我的 Gridview 与 "few rows" 数据绑定时,我当前添加新行的方法是一种适当的设计并且有效 "well"。但是,如果与 "many rows" 数据绑定,我当前添加新行的方法存在缺陷:我正在使用的 EmptyDataTemplate 使用 FooterTemplate[ 公开=39=].因此,如果我有 3 行数据并单击 "Add New Record",网格将重新显示,第 4 行全部 "prepared" 用于数据输入。然而,如果我有 30 行,要插入的行的显示太低,需要滚动。
Protected Sub AddNewRecord(ByVal sender As Object, ByVal e As EventArgs)
GridView1.ShowFooter = True
'rebind data so GridView1_RowDataBound gets a chance to populate the footer
iSubscriberID = Session("SubscriberID")
LoadDataGrid(iSubscriberID)
End Sub
我希望能够改进添加新行的操作,但仍然使用 FooterTemplate。
是否有任何代码可以添加到我的 GridView1_RowDataBound 处理程序中以隐藏现有数据行但仍公开 EmptyDataTemplate 以便通过 FooterTemplate 插入?我试过在那里破解一些东西但没有成功。这是该处理程序的现有代码:
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) _
Handles GridView1.RowDataBound
'-------------------------------------------------------------------------------------------*
' Handle 'Insert' requirements:
' - Bind dropdownlist controls with the possible incumbents and backups for some new position
'-------------------------------------------------------------------------------------------*
If e.Row.RowType = DataControlRowType.Footer Then
' Finding the Dropdown control.
Dim ctrl As Control = e.Row.FindControl("ddlUsers")
If ctrl IsNot Nothing Then
Dim dd As DropDownList = TryCast(ctrl, DropDownList)
dd.DataSource = allUsers
dd.DataBind()
End If
Dim ctrlB As Control = e.Row.FindControl("ddlUsersBackup")
If ctrlB IsNot Nothing Then
Dim ddB As DropDownList = TryCast(ctrlB, DropDownList)
ddB.DataSource = allUsers
ddB.DataBind()
End If
End If
End Sub
我正在为所有列使用 TemplateField 定义;这是一个示例,显示了 FooterTemplate:
的一部分<asp:TemplateField HeaderText="Incumbent">
<ItemTemplate>
<asp:Label ID="lblUser" runat="server" Text='<%# Eval("Incumbent")%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="lblUser" runat="server" Text='<%# Eval("Incumbent")%>' Visible = "false"></asp:Label>
<asp:DropDownList Width="100%" runat="server"
id="ddlUsers" AutoPostBack="true"
DataTextField="FullName" DataValueField="UserID"
OnSelectedIndexChanged="ddlUsers_SelectedIndexChanged">
</asp:DropDownList>
</EditItemTemplate>
<FooterTemplate>
<asp:Label ID="lblUser" runat="server" Text='Set Incumbent'></asp:Label>
<br />
<asp:DropDownList Width="100%" runat="server"
id="ddlUsers" AutoPostBack="true"
DataTextField="FullName" DataValueField="UserID"
OnSelectedIndexChanged="ddlUsers_SelectedIndexChanged">
</asp:DropDownList>
</FooterTemplate>
</asp:TemplateField>
我的另一个可能可行的想法是将页面滚动到底部,以便在使用 ShowFooter=True 重新填充 gridview 时,"insertion" 行始终可见。但是,这似乎涉及一些 Javascript 我希望在此页面上避免的内容。
编辑:2016 年 2 月 18 日 - 尝试将分页添加到 Gridview - 一个新的并发症
@Lesmian - 按照您的建议添加寻呼机很容易,但现在它完全破坏了 Gridview:
我研究了那个错误,但我不明白为什么我的职位强类型集合不支持分页;这是为 Gridview 实例化我的数据源的代码:
Public Class Positions
Implements IEnumerable(Of Position)
Public List As New List(Of Position)
Public Function GetEnumerator() As IEnumerator(Of Position) _
Implements IEnumerable(Of Position).GetEnumerator
Return List.GetEnumerator()
End Function
Private Function GetEnumerator1() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return List.GetEnumerator()
End Function
Public Sub New(ByVal subscriberID As Integer, Optional ByVal filterOnUserID As Integer = 0)
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
Try
cmd = New SqlCommand("dbo.GetPositionsBySubscriberID", connection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@SubscriberID", subscriberID)
cmd.Parameters.AddWithValue("@UserID", filterOnUserID) 'non-zero UserID returns only positions where User is Incumbent or Backup
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
Dim p As Position = New Position(objReader)
List.Add(p)
Loop
objReader.Close()
connection.Close()
解决原问题的加分页器的方法又开辟了一个新的问题。有什么想法吗?
滚动 gridview 需要 javascript,但如果您不想使用它,也许其他方法也适合您的需要。如果您将寻呼机添加到您的 gridview 并在每页中设置少量项目,那么添加新项目将不会导致滚动条出现。然而,使用这种方法我们还有其他缺陷 - 新项目可能会出现在新页面上,因此您应该强制网格显示最后一页,然后新行将始终可见:
Protected Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) _
Handles GridView1.RowCommand
' Insert data if the CommandName == "Insert"
' and the validation controls indicate valid data...
If e.CommandName = "Insert" AndAlso Page.IsValid Then
' Insert new record
GridView1DataSource.Insert()
' Indicate that the user needs to be sent to the last page
SendUserToLastPage = True
End If
End Sub
Protected Sub GridView1_DataBound(sender As Object, e As EventArgs) _
Handles GridView1.DataBound
' Send user to last page of data, if needed
If SendUserToLastPage Then
GridView1.PageIndex = GridView1.PageCount - 1
End If
End Sub
您可以在此处找到此方法的完整示例:http://www.asp.net/web-forms/overview/data-access/enhancing-the-gridview/inserting-a-new-record-from-the-gridview-s-footer-vb
编辑:2016 年 2 月 18 日 - 数据源不支持服务器端数据分页错误
您的自定义集合必须实现 ICollection 接口才能使用 GridView 服务器端分页。 IEnumerable 没有实现 ICollection,这就是您出错的原因。有关 vb 中的实施示例,您可以阅读:https://support.microsoft.com/en-us/kb/306961 and this: http://www.codeproject.com/Articles/265692/Having-fun-with-custom-collections。之后 GridView 应该为您完成剩下的工作。
总体思路:
1. 将您的 GridView 置于固定高度的可滚动 div
2. 在 div 下方放置单行 table 以及您需要插入新记录和 "Add" 按钮
的所有控件
3. 如果可能,使用 SqlDataSource 填充 GridView 并将插入命令包含到 SqlDataSource
4. 在 InsertParameters 块中使用 asp:controlParameter 绑定到新值。
5. 将代码添加到 Add_Click 处理程序
mySqlDataSource.Insert()
PS:更好的是,将您的 GridView 重写为 ListView(.NET 3.5 支持)。这会给你更多的灵活性。例如,您可以将插入放在第一行。
OP 中的实际问题似乎在 post 返回后归结为 "How do I keep the row for inserting in view"。
Page
对象已经有一个名为 Focus
的方法,可用于在页面呈现完成后使特定控件获得焦点。
当位于浏览器可见区域之外的控件获得焦点时,浏览器会将该控件滚动到视图中,以便用户可以看到焦点所在的内容。
因此,要使插入行可见,只需确保在后面的代码中使其可见时将焦点设置在行中合适的控件上。