asp:Gridview getting focused column/lifecycle issue

I am working on a proof of concept (POC) GridView for a much more complex set of functionality where any given cell is filled with a textbox whether it is in normal or edit mode. When any given textbox receives focus (tab or mouse), the row is set to an edit state and it's corresponding textbox in edit mode should receive focus. Once that textbox loses focus it should cause an update on that row. I have the POC working except finding a viable way to select the column ("textbox") that received focus which I believe is a lifecycle issue, but am not coming up with any good workarounds. Please remember this is a POC and there are things I have done that may not be best practice as a quick and dirty way to get it working. I would greatly appreciate any suggestions.

Form:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="StandardContactEditor.aspx.vb" Inherits="EditableGridView.StandardContactEditor" EnableEventValidation="false" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:GridView ID="contactsDataGrid"
                    AllowPaging="true" PageSize="5"
                    DataKeyNames="ID"
                    AutoGenerateColumns="false"

                    runat="server">
                <Columns>
                    <asp:TemplateField HeaderText="First Name">
                        <ItemTemplate>
                            <asp:TextBox ID="txtFirstName" Text='<%# Bind("FirstName") %>' runat="server" />
                        </ItemTemplate>
                        <EditItemTemplate>
                            <asp:TextBox ID="txtFirstNameEdit" Text='<%# Bind("FirstName") %>' runat="server" />
                        </EditItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Last Name">
                        <ItemTemplate>
                            <asp:TextBox ID="txtLastName" Text='<%# Bind("LastName") %>' runat="server" />
                        </ItemTemplate>
                        <EditItemTemplate>
                            <asp:TextBox ID="txtLastNameEdit" Text='<%# Bind("LastName") %>' runat="server" />
                        </EditItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
        </div>
    </form>
</body>
</html>

Code:

Imports FileHelpers

Public Class StandardContactEditor
    Inherits System.Web.UI.Page

    private fileName As String = "C:\TestFiles\TestContacts.csv"
    Private records As List(Of ContactCSV)

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not IsPostBack
            BindGridData()
        End If
    End Sub

    Private Sub BindGridData()
        PopulateRecords()

        Me.contactsDataGrid.DataSource = records
        Me.contactsDataGrid.DataBind()
    End Sub

    Protected Sub RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) Handles contactsDataGrid.RowDataBound
        e.Row.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString(), false)

        If Not ((e.Row.RowState = DataControlRowState.Edit) _
                Or (e.Row.RowState = (DataControlRowState.Alternate Or DataControlRowState.Edit)))
            Try
                ' First Name Column
                Dim firstNameTb As TextBox = e.Row.FindControl("txtFirstName")
                ' firstNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString(), false)

                                    ' ISSUE CAUSED BY APPENDING "000" - Used for col/textbox identification
                firstNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString() + "000", false)
            Catch ex As Exception
                Console.WriteLine()
            End Try

            Try
                Dim lastNameTb As TextBox = e.Row.FindControl("txtLastName")
                ' lastNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString(), false)

                                    ' ISSUE CAUSED BY APPENDING "001" - Used for col/textbox identification
                lastNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString() + "001", false)
            Catch ex As Exception
            End Try
        End If
    End Sub

    Protected Sub RowEditing(ByVal sender As Object, ByVal e As GridViewEditEventArgs) Handles contactsDataGrid.RowEditing
        contactsDataGrid.EditIndex = (e.NewEditIndex / 1000)
        Dim col As Integer = (e.NewEditIndex Mod 1000)

        ' contactsDataGrid.EditIndex = e.NewEditIndex

        BindGridData()

        Dim fntb As TextBox = contactsDataGrid.Rows(contactsDataGrid.EditIndex).FindControl("txtFirstNameEdit")
        fntb.Attributes("onblur") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Update$" + contactsDataGrid.EditIndex.ToString(), false)
        ' fntb.Focus()

        Dim lntb As TextBox = contactsDataGrid.Rows(contactsDataGrid.EditIndex).FindControl("txtLastNameEdit")
        lntb.Attributes("onblur") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Update$" + contactsDataGrid.EditIndex.ToString(), false)
        ' lntb.Focus()

        If(col = 0)
            fntb.Focus()
        Else If(col = 1)
            lntb.Focus()
        End If
    End Sub

    Protected Sub RowUpdating(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs) Handles contactsDataGrid.RowUpdating
                    ' AT THIS POINT THE EDIT FIELDS ARE NOT VISIBLE AND AN EXCEPTION IS THROWN WHEN TRYING TO RETRIEVE THOSE TEXTBOXES

        ' Trying to override here
        contactsDataGrid.EditIndex = (contactsDataGrid.EditIndex / 1000)

        PopulateRecords()

        Dim id As String = contactsDataGrid.DataKeys(e.RowIndex).Value.ToString()

        Dim record As ContactCSV = records.Where(Function(x) x.ID = id).SingleOrDefault()

        Dim firstNameTb As TextBox = contactsDataGrid.Rows(e.RowIndex).FindControl("txtFirstNameEdit")
        record.firstName = firstNameTb.Text

        Dim lastNameTb As TextBox = contactsDataGrid.Rows(e.RowIndex).FindControl("txtLastNameEdit")
        record.lastName = lastNameTb.Text

        WriteRecordsToFile()

        contactsDataGrid.EditIndex = -1

        ' update the actual data
        contactsDataGrid.DataSource = records
        contactsDataGrid.DataBind()
    End Sub

    Protected Sub SelectedColumn(ByVal Sender As Object, ByVal e As EventArgs)
        Console.WriteLine()
    End Sub

    Private Sub PopulateRecords()
        Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))

        Try
            Dim objs As ContactCSV() = fileEngine.ReadFile(fileName)
            records = objs.ToList()
        Catch ex As exception

        End Try
    End Sub

    Private Sub WriteRecordsToFile()
        Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))

        fileEngine.WriteFile(fileName, records)
    End Sub
End Class

Answers


This was a classic case of over-thinking a solution with a combination of an unfamiliar technology. The idea was to build a highly responsive (per field edit) page. Rather than mix any built-in GridView functionality, a simple OnTextChanged worked as I expected after everything else was stripped out. The problem turned out with the previous code posted is after an OnBlur, with the column identification parts in place, a row was set to Alternate state rather than Alternate Or Edit state.

Form:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="StandardContactEditor.aspx.vb" Inherits="EditableGridView.StandardContactEditor" EnableEventValidation="true" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:GridView ID="contactsDataGrid"
                    AllowPaging="true" PageSize="5"
                    DataKeyNames="ID"
                    AutoGenerateColumns="false"

                    runat="server">
                <Columns>
                    <asp:TemplateField HeaderText="First Name">
                        <ItemTemplate>
                            <asp:TextBox ID="txtFirstName" Text='<%# Bind("FirstName") %>' OnTextChanged="textBox_TextChanged" AutoPostBack="true" runat="server" />
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Last Name">
                        <ItemTemplate>
                            <asp:TextBox ID="txtLastName" Text='<%# Bind("LastName") %>' OnTextChanged="textBox_TextChanged" AutoPostBack="true" runat="server" />
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Phone Number">
                        <ItemTemplate>
                            <asp:TextBox ID="txtPhoneNumber" Text='<%# Bind("PhoneNumber") %>' OnTextChanged="textBox_TextCHanged" AutoPostBack="true" runat="server" />
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
        </div>
    </form>
</body>
</html>

Code:

Imports FileHelpers

Public Class StandardContactEditor
    Inherits System.Web.UI.Page

    private fileName As String = "C:\TestFiles\TestContacts.csv"
    Private records As List(Of ContactCSV)

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not IsPostBack
            BindGridData()
        End If
    End Sub

    Private Sub BindGridData()
        PopulateRecords()

        Me.contactsDataGrid.DataSource = records
        Me.contactsDataGrid.DataBind()
    End Sub

    Protected Sub textBox_TextChanged(ByVal sender As Object, ByVal e As EventArgs)
        PopulateRecords()

        Dim tb as TextBox = sender
        Dim row As GridViewRow = tb.Parent.Parent

        Dim record As ContactCSV = records.Where(Function(x) x.ID = row.RowIndex).SingleOrDefault()

        Dim firstNameTb As TextBox = contactsDataGrid.Rows(row.RowIndex).FindControl("txtFirstName")
        record.firstName = firstNameTb.Text

        Dim lastNameTb As TextBox = contactsDataGrid.Rows(row.RowIndex).FindControl("txtLastName")
        record.lastName = lastNameTb.Text

        Dim phoneNumberTb As TextBox = contactsDataGrid.Rows(row.RowIndex).FindControl("txtPhoneNumber")
        record.PhoneNumber = phoneNumberTb.Text

        WriteRecordsToFile()
    End Sub

    Private Sub PopulateRecords()
        Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))

        Try
            Dim objs As ContactCSV() = fileEngine.ReadFile(fileName)
            records = objs.ToList()
        Catch ex As exception

        End Try
    End Sub

    Private Sub WriteRecordsToFile()
        Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))

        fileEngine.WriteFile(fileName, records)
    End Sub
End Class

Need Your Help

.net - What is the best practice for securing WPF application configuration settings?

.net wpf application-security

I am aware that this is a more subjective question than is preferred, but I couldn't think of a better place or way to ask it.

Creating a concatenated string of ints Python

python loops concatenation

I am iterating through some range of numbers and creating a string of concatenated numbers that fit my criteria. However, I'm not getting the output that I want. I'm new to python, so I might be mi...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.