Share via


Gridview's SelectedIndexChanged Event handler no longer works after Gridview added to Ajax Update Panel.

Question

Monday, January 22, 2007 2:31 PM

I am adding Ajax update panels to my existing web app which has been working great for some time. I've got 90% of the site update-panalized :) but I'm stuck on 1 last page.

 The page contains a large gridview containing summary data, when the "View" button is pressed (selects the gridview row) I have an event handler which creates a javascript pop up window that loads a details page based on selected index's MeetingID value.  It does this by adding a Page.ClientScript.RegisterClientScriptBlock to the top of the rendered page, and a Page.ClientScript.RegisterStartupScript to the very bottom of the rendered page.  And again worked until the page contents were added to an update panel.  I'm sure the problem is related to partial page rendering, where the javascripts on the top and bottom of the rendered page are not being updated or executed because only the gridview is being refreshed... I'm not sure how to get this working again.   The ajax code is working, the selected row does highlight, and if I add test code to the SelectedIndexChanged event... I can see that the test code does fire, but there is no longer a pop up details window when the View button is pressed on the Gridview.  No errors are showing either.   Here is the code I'm working with:

Code Behind  

Protected Sub GridView1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.SelectedIndexChanged

Dim type As Type = Me.GetType()

Dim topKey, footKey As String

Dim topScript, footScript As String

topKey = "JavaFunctions"

topScript = "<script type='text/javascript'>" + ControlChars.CrLf + _

"<!--" + ControlChars.CrLf + _

"function openwindow() {" + ControlChars.CrLf + _

"var leftVal=(screen.width / 2) - 302;" + ControlChars.CrLf + _

"var topVal = (screen.height / 2) - 400;" + ControlChars.CrLf + _

"newWindow = window.open('MeetingDetail.aspx?MeetingID=" + GridView1.Rows(GridView1.SelectedIndex).Cells(2).Text + "',null,'width=605,height=700,left='+leftVal+',top='+topVal+'')" + ControlChars.CrLf + _

"}" + ControlChars.CrLf + _

"// -->" + ControlChars.CrLf + _

"</script>"

Page.ClientScript.RegisterClientScriptBlock(type, topKey, topScript)

footKey = "DetailPopUp"

'footScript = "<script type='text/javascript'>" + ControlChars.CrLf + "window.open('MeetingDetail.aspx?MeetingID=" + GridView1.Rows(GridView1.SelectedIndex).Cells(2).Text + "',null,'width=605,height=700',null)" + ControlChars.CrLf + ";</script>"

footScript = "<script type='text/javascript'>window.onload=openwindow();</script>"

Page.ClientScript.RegisterStartupScript(type, footKey, footScript)

End Sub

End Code Behind

 

 ASPX Page  

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server" >

<ajax:ScriptManager ID="ScriptManager1" runat="server">

</ajax:ScriptManager>

<ajax:UpdatePanel ID="UpdatePanel1" runat="server">

<ContentTemplate>

Meeting Status: <asp:DropDownList ID="ddlStatusID" AppendDataBoundItems="True" runat="server" AutoPostBack="True" DataSourceID="ObjectDataSource1"

DataTextField="StatusDesc" DataValueField="StatusID">

<asp:ListItem Selected="True" Value="0">All</asp:ListItem>

</asp:DropDownList><br />

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetCostSavingsStatuses" TypeName="DirectMeetingsTableAdapters.tblStatusTableAdapter">

<DeleteParameters>

<asp:Parameter Name="Original_StatusID" Type="Int32" />

</DeleteParameters>

<UpdateParameters>

<asp:Parameter Name="StatusID" Type="Int32" />

<asp:Parameter Name="StatusDesc" Type="String" />

<asp:Parameter Name="Hide" Type="Boolean" />

<asp:Parameter Name="Original_StatusID" Type="Int32" />

</UpdateParameters>

</asp:ObjectDataSource>

<asp:GridView ID="GridView1" CellSpacing="1" runat="server" AutoGenerateColumns="False" DataSourceID="GetSavingsSummaryData" CellPadding="4" ForeColor="#333333" GridLines="None" AllowSorting="True" ShowFooter="True">

<Columns>

<asp:CommandField ButtonType="Button" SelectText="View" ShowSelectButton="True" />

<asp:BoundField DataField="StatusDesc" HeaderText="Status" SortExpression="StatusDesc" />

<asp:BoundField DataField="MeetingID" HeaderText="HB ID" SortExpression="MeetingID" />

<asp:BoundField DataField="DirectMeetingsID" HeaderText="DM ID" SortExpression="DirectMeetingsID" />

<asp:BoundField DataField="MeetingName" HeaderText="Program Name" SortExpression="MeetingName" />

<asp:BoundField DataField="StartDate" HeaderText="Start Date" SortExpression="StartDate" DataFormatString="{0:d}" HtmlEncode="False" />

<asp:BoundField DataField="RoomNights" HeaderText="Room Nights" SortExpression="RoomNights" />

<asp:BoundField DataField="RoomSavings" HeaderText="Room Savings" SortExpression="RoomSavings" DataFormatString="{0:c}" HtmlEncode="False" />

<asp:BoundField DataField="MtgSavings" HeaderText="Meeting Savings" SortExpression="MtgSavings" DataFormatString="{0:c}" HtmlEncode="False" />

<asp:BoundField DataField="OtherSavings" HeaderText="Other Savings" SortExpression="OtherSavings" DataFormatString="{0:c}" HtmlEncode="False" />

<asp:BoundField DataField="QuotedCost" HeaderText="Quoted Cost" SortExpression="QuotedCost" DataFormatString="{0:c}" HtmlEncode="False" />

<asp:BoundField DataField="ContractedCost" HeaderText="Contracted Cost" SortExpression="ContractedCost" DataFormatString="{0:c}" HtmlEncode="False" />

<asp:BoundField DataField="TotalSavings" HeaderText="Total Savings" ReadOnly="True"

SortExpression="TotalSavings" DataFormatString="{0:c}" HtmlEncode="False" />

</Columns>

<FooterStyle BackColor="#6B86A4" Font-Bold="True" ForeColor="White" />

<RowStyle BackColor="#EFF3FB" />

<EditRowStyle BackColor="#2461BF" />

<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />

<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />

<HeaderStyle BackColor="#6B86A4" Font-Bold="True" ForeColor="White" />

<AlternatingRowStyle BackColor="White" />

</asp:GridView>

<asp:SqlDataSource ID="GetSavingsSummaryData" runat="server" ConnectionString="<%$ ConnectionStrings:DirectMeetingsConnectionString %>"

SelectCommand="spCostSavingsSummary" SelectCommandType="StoredProcedure">

<SelectParameters>

<asp:QueryStringParameter DefaultValue="1" Name="ClientID" QueryStringField="CompanyID"

Type="Int32" />

<asp:ControlParameter ControlID="ddlStatusID" DefaultValue="" Name="StatusID" PropertyName="SelectedValue"

Type="String" />

</SelectParameters>

</asp:SqlDataSource>

</ContentTemplate>

</ajax:UpdatePanel>

</asp:Content>

 

  End ASPX Page  

 Thanks in advance for any advice you may have!

- David

 

All replies (10)

Thursday, March 1, 2007 1:11 PM âś…Answered

Hi, David !

 Instead of try to make select button causes postback, use shared members of scriptManager class to register your javascript, instead of Page class. This will solve your problem.

 []'s

Dennes


Tuesday, January 23, 2007 1:10 PM

I confirmed that the ScriptBlocks are not being added to the page after selecting a gridview row when it is in an update panel.  When I view the update panel version of the page and select a row, the row highlights, I then used the browser "view source" the following script blocks ARE NOT present... these are the script blocks that appear in the resulting rendered page on the working version:

Found at the top near the <BODY> tag:

<!--
function openwindow() {
var leftVal=(screen.width / 2) - 302;
var topVal = (screen.height / 2) - 400;
newWindow = window.open('MeetingDetail.aspx?MeetingID=100109',null,'width=605,height=700,left='+leftVal+',top='+topVal+'')
}
// -->
</script>

 Found near the </Body> tag:

<script type='text/javascript'>window.onload=openwindow();</script>

 

Again these two script blocks are never rendered in the page after adding the update panel.  These script blocks are supposed to be added to the page when the SelectedIndexChanged event fires.   Any idea how to get this working again?


Friday, January 26, 2007 11:00 AM

I think its all about asking the right question... I hope.  Can someone answer this.

How do I trigger a full page postback from within an update panel? 

I have a select button enabled gridview within an update panel.  When someone selects a gridview row I need the full page to load, as I need to affect portions of the page outside the update panel.

I am using AJAX 1.0


Friday, January 26, 2007 12:54 PM

If I understand what you're asking for correctly, all you need to do is add the following after your </contenttemplate> tag in your updatepanel:

 

<Triggers>
   <asp:PostBackTrigger ControlID="GridView1" />
</Triggers>

 

where GridView1 represents the name of the control you wish to trigger the full page postback. 

 

 


Friday, January 26, 2007 1:17 PM

Thanks for the post Danehrig, this might be really close to the answer.  Let me explain a little further.

The reason the Gridview is inside of the Update panel in the first place is to enable smooth async postbacks when sorting columns as well as when filtering the gridview results with outside controls (also within the update panel).

I'd like to keep the async postbacks for all gridview events EXCEPT when the row Select button is pressed in the control column of the gridview. 

I have a SelectedIndexChanged event handler that needs to update portions of the page outside of the updatepanel. The selectedindexchanged handler fires during async postbacks, but its results are not seen on portions of the page outside the update panel.

 Is there a way to modify your PostBackTrigger to specify the specific GridView1 event (Select Button)... instead of the entire Gridview Control?


Friday, January 26, 2007 2:38 PM

I think it would be is simple as placing the entire contents of the page you want updated in the contents of an updatepanel.  You can nest them:

  

    <form runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="PageUpdatePanel" runat="server">
            <ContentTemplate>
                <asp:Label ID="UserName" runat="server"></asp:Label>
                <asp:UpdatePanel ID="GridViewUpdatePanel" runat="server">
                    <ContentTemplate>
                        <asp:GridView ID="GridView1" runat="server" AllowPaging="True" DataSourceID="SqlDataSource1"
                            OnSelectedIndexChanged="GridView1_SelectedIndexChanged">
                            <Columns>
                                <asp:CommandField ShowSelectButton="True" />
                            </Columns>
                        </asp:GridView>
                        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:WebDB1Pool %>"
                            SelectCommand="select emp_fn, emp_ln from webtest.dbo.web_demog order by emp_ln">
                        </asp:SqlDataSource>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>

 my code behind looks like this:

      protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
    {
        UserName.Text = GridView1.SelectedRow.Cells[1].Text + " " + GridView1.SelectedRow.Cells[2].Text;
    }

 

This updates the label to show the first and last name of the user when you select.

Anyway the point is:  You can nest updatepanels inside each other. 

 

 


Friday, January 26, 2007 3:46 PM

I have tried this as well,  expanding the size of the update panel to contain the entire page, so that the async postbacks would include the the page changes in my selectedindexchanged event.

Unfortunately the output of this event,  Page.ClientScript.RegisterClientScriptBlock(), and Page.ClientScript.RegisterStartupScript(), always appears in the resulting browser (view source) just before, and just after any scriptmanager or updatepanel content on the page. This block is generated before any page content is added to the resulting HTML Code.

 Basicly the RegisterClientScriptBlock method creates a <script type='text/javascript'> </script> block at the very top of page that contains a function that pops open a new broswer window that contains details on the item they selected in the gridview.

The RegisterStartupScript renders another <script type='text/javascript'></script> at the very bottom of the page after all the HTML added from your aspx file including updatepanels.

The only way to create/refresh these script blocks is for the full page to load.

This is why I was hoping to call a full postback trigger from a sub object of the gridview.  The gridview is basicly the whole page content.  Adding the postback trigger to the full gridview object would result in having no async post backs.  It would be the same as removing the AJAX completely for this page which is where I started.

What do you think... and thank you so much for your input so far!


Monday, January 29, 2007 10:16 AM

I see your dilemma now.  I'm not sure if you're going to be able to do this with an updatepanel.  The two things that spring to mind are:

 

1) add the code to generate the script into your selectedindexchanged function and see if that does the trick

2) add a button that becomes visible after you do a select on the gridview with a full postback trigger for it.

 Honestly I haven't used the page methods you're referring to.  Did this stuff work for you in RC1/ the betas?
 


Monday, January 29, 2007 4:46 PM

I found out that there is a way to have items like buttons within a gridview marked to cause a full postback when clicked called RegisterPostBackControl().

http://ajax.asp.net/docs/mref/M_System_Web_UI_ScriptManager_RegisterPostBackControl_1_62fe17e7.aspx

So I wrote the following gridview row bound event handler.  Which compiles with no errors, but still the Select button (ID="Button1") on each gridview row does not cause a full postback... they are still async/partial postbacks.  Can you see what I'm doing wrong?

Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) Handles GridView1.RowDataBound

If e.Row.RowType = DataControlRowType.DataRow Then

Dim PostBack As New System.Web.UI.ScriptManager

Dim selectButton As Button = CType(e.Row.FindControl("Button1"), Button)

PostBack.RegisterPostBackControl(selectButton)

End If

End Sub


Monday, January 29, 2007 7:56 PM

Try this:

 

Whole page is wrapped in a UpdatePanel and let's give it an id of "MainPageUpdatePanel"

then wrap your gridview with a panel (for my purposes will call it GridViewUpdatePanel).

and it should be inside the MainPageUpdatePanel.

 

In your codebehind or code beside add in where you process the edit record event:

UpdatePanel MainPageUpdatePanel = (UpdatePanel)FindControl("MainPageUpdatePanel");

if (MainPageUpdatePanel !=null)

{

MainPageUpdatePanel.UpdatePanel();

}

Since the gridview modal is inside everything will get updated.   If I am understanding your problem then this will update most.  If you need to perform binding as if it was a page refresh - check out my blogs on how I manipulate modals and gridviews on the same page and use spoof parmeters to mimic how the page would actually be rendered in a normal non-ajax environment but still retain the ajax mojo...