When my Gridview is bound with "few rows" of data, my current approach for adding a new row is an adequate design and works "well". However, if bound with "many rows" of data, my current approach for adding a new row is flawed: the EmptyDataTemplate I am using is exposed using the FooterTemplate. Thus, if I have 3 rows of data and click "Add New Record", the grid is redisplayed with a 4th row all "prepared" for data entry. Yet if I have 30 rows, the display of the row to be inserted is so far down it requires a scroll.
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
I'm hoping to be able to improve the operation of adding a new row BUT still use the FooterTemplate.
Is there any code that could be added to my GridView1_RowDataBound handler to hide existing data rows but still expose the EmptyDataTemplate for insertion via the FooterTemplate? I've tried hacking a few things there without success. Here is my existing code for that handler:
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
I'm using TemplateField definitions for all the columns; here is one example that shows a part of the 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>
Another idea I had that might work would be to scroll the page to the bottom so the "insertion" line is always visible when repopulating the gridview with ShowFooter=True. However, that seems to involve some Javascript which I'd prefer to avoid on this page.
EDIT: 18 Feb 2016 - Attempt to add Paging to Gridview - a new complication
@Lesmian - adding a pager as you suggested was easy but now it totally breaks the Gridview:
I researched that error and I cannot see why my strongly-typed collection for Positions cannot support paging; here is the code that instantiates my data source for the 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()
The approach of adding a pager to solve the original problem has opened up a new issue. Any thoughts on that?
The actual question in the OP seems to boil down to "How do I keep the row for inserting in view" after post back.
The Page
object already has a method called Focus
which can be used to cause a specific control to receive focus after the page rendering is complete.
When a control that is outside of the visible area of the browser receives focus, the browser will scroll that control into view so the user can see what is focused.
So to make the insert row visible, just make sure to set focus on a suitable control in the row when you make it visible in the code behind.