Search code examples
asp.netvb.netwebformsasp.net-ajaxaspxgridview

Data binding fails to change values for custom control inside GridView inside an UpdatePanel


I am creating a GridView inside an UpdatePanel like this:

<asp:ScriptManager runat="server" EnablePartialRendering="true" />

<div id="masterHistoryDialog" style="display: none">
    <asp:UpdatePanel runat="server" ChildrenAsTriggers="true" UpdateMode="Always">
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="historyRepeater" EventName="PageIndexChanging" />
        </Triggers>
        <ContentTemplate>
            <asp:GridView ID="historyRepeater" AutoGenerateColumns="false" runat="server" AllowPaging="true" AllowSorting="false" PagerSettings-NextPageText="Next" PagerSettings-PreviousPageText="Previous" PageSize="4" OnPageIndexChanging="historyRepeater_PageIndexChanging">
                <Columns>
                    <asp:TemplateField>
                        <ItemTemplate>
                            <uc:CustomCalendarControl ChangeID='<%# DataBinder.Eval(Container.DataItem, "Item1") %>' ScheduleID='<%# DataBinder.Eval(Container.DataItem, "Item2") %>' runat="server" />
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
        </ContentTemplate>
    </asp:UpdatePanel>
</div>

The PageIndexChanging event fires as expected, calling the following event handler:

Protected Sub historyRepeater_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
    historyRepeater.PageIndex = e.NewPageIndex
    historyRepeater.DataSource = GetSchedules()
    historyRepeater.DataBind()
End Sub

CustomCalendarControl is a custom control.

I confirmed that GetSchedules is, in fact, getting my entire data set.

I page the data and have 4 custom controls per page (total of 20 items on 5 pages). The first page works correctly. However, when I try to navigate to one of the other pages, the initialization of the custom control fails because it's not getting the actual values of ChangeID or ScheduleID - they're always 0.

It fails when I do the call to DataBind() because initialization of the custom control depends on ChangeID and ScheduleID being actual IDs.

How can I fix this issue?


Solution

  • Your problem has to do at which moment the nested User Controls populate its client side content. This happens first for the Control and then the GridView, so the UserControl has already been build before the values of ChangeID and ScheduleID are set.

    One way to solved this is to manually call the building of the Control from the Parent.

    First, modify the UserControl so that it has a public function to properly display the values

    public string ChangeID { get; set; }
    public string ScheduleID { get; set; }
    
    protected void Page_Load(object sender, EventArgs e)
    {
        setUCValues();
    }
    
    public void setUCValues()
    {
        Label1.Text = ChangeID;
        Label2.Text = ScheduleID;
    }
    
    
    Public Property ChangeID As String
        Get
        End Get
        Set
        End Set
    End Property
    
    Public Property ScheduleID As String
        Get
        End Get
        Set
        End Set
    End Property
    
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        setUCValues
    End Sub
    
    Public Sub setUCValues()
        Label1.Text = ChangeID
        Label2.Text = ScheduleID
    End Sub
    

    Next, add an ID to the UserControl in the GridView

    <uc:CustomCalendarControl ID="calendarControl" runat="server" ChangeID=
    

    Then in the PageIndexChanging, loop all the rows and call the function

    protected void historyRepeater_PageIndexChanging(object sender, GridViewPageEventArgs e)
    {
        //databinding
    
        foreach (GridViewRow row in historyRepeater.Rows)
        {
            WebUserControl1 control = row.FindControl("calendarControl") as WebUserControl1;
            control.setUCValues();
        }
    }
    
    
    Protected Sub historyRepeater_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
        'databinding
    
        For Each row As GridViewRow In historyRepeater.Rows
            Dim control As WebUserControl1 = CType(row.FindControl("calendarControl"),WebUserControl1)
            control.setUCValues
        Next
    End Sub