Search code examples
asp.netgridviewajaxcontroltoolkitlinkbutton

ASP.NET LinkButton in GridView causing full postback


This one is REALLY driving me nuts. I've read, and tried, most of the workarounds but still it posts back!!

All the markup is generated dynamically from code-behind and inserted into a page that is part of a Master Page, from the init event.

There are a series of nested tabs, the tab content for the most part is data in a GridView. Each Gridview is set in it's own update panel. Every time a LinkButton in the GridView is clicked there is a full postback causing the tabs to reset (any button outside of the GridView and in the UpdatePanel doesn't cause a full postback.

LinkButtons are generated like this

 Dim Select_Field As New CommandField
        With Select_Field
            .HeaderText = "View Transactions"
            .SelectText = "View Transactions"
            .ShowSelectButton = True
        End With
        GV.Columns.Add(Select_Field)

Registering with ToolKitScriptManager

Private Sub AssessmentsMain_RowDataBound(sender As Object, e As GridViewRowEventArgs)
    Try
        If e.Row.RowType = DataControlRowType.DataRow Then
            Dim vID As Integer = Convert.ToInt32(DataBinder.Eval(e.Row.DataItem, "ID"))
            Dim LB As LinkButton = CType(e.Row.Cells(4).Controls(0), LinkButton)
            LB.ID = "AssMain_" & vID
            AjaxControlToolkit.ToolkitScriptManager.GetCurrent(Me).RegisterAsyncPostBackControl(LB)
        End If
    Catch ex As Exception
        Dim vError As New SendError
        vError.MailError("840", PageName, ex)
        ShowError()
    End Try
End Sub

and the generated markup for one row is like this

<tr class="GridView" style="color:#333333;background-color:#F7F6F3;">
<td>10</td>
<td>Adam White</td>
<td>4224 Res Road</td>
<td align="right">$6,850.65</td>
<td>
<a id="ctl00_ContentPlaceHolder1_AssessmentsMainGV_ctl02_AssMain_10"  href="javascript:__doPostBack(&#39;ctl00$ContentPlaceHolder1$AssessmentsMainGV&#39;,&#39;Select$0&#39;)" style="color:#333333;">View Transactions</a>

The GridView class

Public Class HAS_Gridview
    Inherits GridView
    Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
        MyBase.OnInit(e)
        CellPadding = 4
        GridLines = WebControls.GridLines.None
        ForeColor = Drawing.ColorTranslator.FromHtml("#333333")
        ClientIDMode = UI.ClientIDMode.AutoID
        With MyBase.FooterStyle
            .BackColor = Drawing.ColorTranslator.FromHtml("#E2DED6")
            .Font.Bold = True
            .ForeColor = Color.White
        End With
        RowStyle.BackColor = Drawing.ColorTranslator.FromHtml("#F7F6F3")
        RowStyle.ForeColor = Drawing.ColorTranslator.FromHtml("#333333")
        PagerStyle.HorizontalAlign = WebControls.HorizontalAlign.Center
        PagerStyle.ForeColor = Color.Black
        PagerStyle.BackColor = Drawing.ColorTranslator.FromHtml("#E2DED6")
        With MyBase.SelectedRowStyle
            .BackColor = Drawing.ColorTranslator.FromHtml("#E2DED6")
            .Font.Bold = True
            .ForeColor = Drawing.ColorTranslator.FromHtml("#333333")
        End With
        With MyBase.HeaderStyle
            .BackColor = Drawing.ColorTranslator.FromHtml("#E2DED6")
            .Font.Bold = True
            .ForeColor = Color.Black
            .CssClass = "GridView"
        End With
        EditRowStyle.BackColor = Drawing.ColorTranslator.FromHtml("#999999")
        With MyBase.AlternatingRowStyle
            .BackColor = Color.White
            .ForeColor = Drawing.ColorTranslator.FromHtml("#284775")
            .CssClass = "GridView"
        End With
        With MyBase.RowStyle
            .CssClass = "GridView"
        End With
    End Sub

End Class

Solution

  • In the end the only way I could get this to work was

    Create a class for a LinkButton Template

    Public Class LinkButtonTemplate
        Implements ITemplate
        Private m_ColumnName As String
        Event LinkButtonItem_Clicked(sender As LinkButton, e As EventArgs)
        Public Property ColumnName() As String
            Get
                Return m_ColumnName
            End Get
            Set(ByVal value As String)
                m_ColumnName = value
            End Set
        End Property
        Public Sub New()
        End Sub
        Public Sub New(ByVal ColumnName As String)
            Me.ColumnName = ColumnName
        End Sub
        Public Sub InstantiateIn(container As Control) Implements ITemplate.InstantiateIn
            Dim LB As New LinkButton()
            With LB
                .ID = "LB_" & ColumnName
                .Text = ColumnName
                .OnClientClick = "LinkButtonClick(this);"
           End With
          container.Controls.Add(LB)
        End Sub
     End Class
    

    Add this javascript so that it would post the ID to a hidden field and click a hidden button

    Private Sub LoadLinkButtonClick()
        Try
            Dim SB As New StringBuilder
            SB.Append("function LinkButtonClick(LinkButton){ ")
            SB.Append("setTimeout(function() { ")
            SB.Append("$get('" & GridViewLBClicked.ClientID & "').click(); ")
            SB.Append(" }, 300); ")
            SB.Append("var sendingID = LinkButton.id; ")
            SB.Append("document.getElementById('" & HiddenField1.ClientID & "').value = sendingID; ")
            SB.Append("} ")
            ScriptManager.RegisterStartupScript(Me, Me.GetType(), "LoadLinkButton", SB.ToString, True)
        Catch ex As Exception
            Dim vError As New SendError
            vError.MailError("1229", PageName, ex)
        End Try
    End Sub
    

    On the RowDataBound event capture the ID we need and add it to the LinkButton ID (so now we know both the sending GridView and the selected row)

    Private Sub AssessmentsMain_RowDataBound(sender As Object, e As GridViewRowEventArgs)
        Try
            If e.Row.RowType = DataControlRowType.DataRow Then
                Dim vID As Integer = Convert.ToInt32(DataBinder.Eval(e.Row.DataItem, "ID"))
                Dim LB As LinkButton = CType(e.Row.Cells(4).Controls(0), LinkButton)
                LB.ID = "AssMain_" & vID
            End If
        Catch ex As Exception
            Dim vError As New SendError
            vError.MailError("840", PageName, ex)
            ShowError()
        End Try
    End Sub
    

    From the hidden button click we can recover all the data we need to make the async postback

    Private Sub RaiseLinkButton_Click(sender As Object, e As EventArgs)
        Try
            Dim vFunction As New Functions
            Dim vValue As String = HiddenField1.Value
            Dim vSplit = vValue.Split("_")
            Dim i As Integer = 0
            For Count As Integer = 0 To vSplit.Length - 1
                i += 1
            Next
            Dim DGName As String = vSplit(i - 2)
            Select Case DGName
                Case "AssMain"
                    Dim MV As MultiView = vFunction.FindControlRecursive(BodyMain, "AssessmentMultiView")
                    Dim GV As CustomControl.HAS_Gridview = vFunction.FindControlRecursive(BodyMain, "AssessmentDetailGV") 
                    With GV
                        .DataSource = AssessmentsDetail_ReturnDataSet()
                        .DataBind()
                        .PageIndex = 0
                    End With
    
                    MV.ActiveViewIndex = 1
    
                    Dim vPanel As UpdatePanel = vFunction.FindControlRecursive(BodyMain, "AssessmentUpdatePanel")
                    vPanel.Update()
    
    
            End Select
    
        Catch ex As Exception
            Dim vError As New SendError
            vError.MailError("953", PageName, ex)
            ShowError()
        End Try
    End Sub