0

I'd like to use a custom control within a repeater with access to the data item of the repeater from within the custom control. This works fine when loading the page, but when binding data to the repeater from a button click event it will not work.

Over the past fwe days I have tried so many different approaches, using ViewStates, Session, disabling ViewState, doing things with and without update panels but I always end at the same issue. For some reason when binding data on the repeater in the button click event handler the "AssignedValue" property of the custom control will not be set, which works on page load without postback.

I am confused, as the repeater item is present but the custom control is loaded without it being assigned to "AssignedValue". How else would I bind a different data set to the repeater when clicking a button?

Any ideas how I can solve this issue?

Demo solution download: https://drive.google.com/file/d/10TvaCr0p6wPkQ6HoA0PnjwXgYgVJEKp8/view?usp=sharing or see the code below.

Default.aspx

<%@ Page Title="Home Page" Language="VB" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.vb" Inherits="WebApplication1._Default" %>
<%@ Register TagPrefix="test" Src="~/WebUserControl1.ascx" TagName="ctrl" %>

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    <asp:UpdatePanel runat="server">
        <ContentTemplate>
            <asp:Repeater runat="server" ID="rptTest" ItemType="WebApplication1.Test">
                <ItemTemplate>
                    <div>
                        <test:ctrl runat="server" AssignedValue="<%# Item.Value %>" /> (Item: <%# Item.Value %>)
                    </div>
                </ItemTemplate>
            </asp:Repeater>
            <br />
            <asp:LinkButton runat="server" ID="btnLoadMore" OnClick="btnLoadMore_Click">Load More!</asp:LinkButton>
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Default.aspx.vb

Public Class _Default
    Inherits Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        If Not IsPostBack Then
            rptTest.DataSource = Test.Set1
            rptTest.DataBind()
        End If
    End Sub

    Protected Sub btnLoadMore_Click(sender As Object, e As EventArgs)
        rptTest.DataSource = Test.Set2
        rptTest.DataBind()
    End Sub
End Class

Test.vb

Public Class Test
    Public Property Value As String

    Public Shared Property Set1 As Test() = {New Test() With {.Value = "a"}, New Test() With {.Value = "b"}}
    Public Shared Property Set2 As Test() = {New Test() With {.Value = "c"}, New Test() With {.Value = "d"}}
End Class

WebUserControl1.aspx

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="WebUserControl1.ascx.vb" Inherits="WebApplication1.WebUserControl1" %>
Value: <asp:Literal runat="server" ID="litValue" />

WebUserControl.aspx.vb

Public Class WebUserControl1
    Inherits System.Web.UI.UserControl

    Public Property AssignedValue As String

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        litValue.Text = AssignedValue
    End Sub

End Class

What I expect:

Value: a (Item: a)
Value: b (Item: b)
*Click on Load More!*
Value: c (Item: c)
Value: d (Item: d)

What I get:

Value: a (Item: a)
Value: b (Item: b)
*Click on Load More!*
Value: (Item: c)
Value: (Item: d)
7
  • Try setting to test2 the first time around. The grid, listview, or repeater will be starting over from scratch EACH time you re-bind. So you could eliminate all the test1 code code and right off the bat bind to test2 the first time. And a self refencing class - well that certainly adds to the confusing. here. Create a whole new class that references and creates instances of the first class - that would help here too. But unless you persist a instance of the class you create in code (say shove the instance you create into session(),and then pull + get class from session and add more + rebind. Commented Feb 11, 2021 at 16:37
  • Remember, these controls persist the data you shove into them, but NOT the data source used. Data source must be recreated for a re-bind, or you have to save the data source in view state or session to add or remove from that given data source. (or do what the wizards often do - they place a data adaptor on the page that also persists the data source. (I don't like those things on my page - but at the end of the day, you have to persist the data source to add to, or re-create in total from scratch in total with the additonal data. I wish these controls did persist data sources - they don't. Commented Feb 11, 2021 at 16:43
  • @AlbertD.Kallal I'm not sure what you mean by test1 and test2. Do you mean Set1 and Set2? The point of the whole exercise is to have two different data sets, so binding to Set2 in the beginning would be pointless. The set of pre-defined values in Test (Set1, Set2, what I assume you mean by self-referencing) is definitely not an issue and the self-referencing is perfectly fine. The data is not supposed to persist between the initial load of the page and the button click, the datasource is overwritten with Set2, I don't want to add to the datasource, I am overwriting it with no persistence. Commented Feb 11, 2021 at 16:49
  • I feel like I have not properly conveyed what the issue is. The custom controls take a value as attribute which works fine. Only when in a postback does the custom control initialise (eg. Control.Load is called) without having the value, that is clearly there (see bottom of the question What I expect/What I get) assigned to it. "AssignedValue" is properly filled in one case, and null in another. Commented Feb 11, 2021 at 16:57
  • Yes, I did mean set2. All the code before is 100% not relevant. You are re-binding from scratch with a new source. So just test your code with set2 – the set1 code does not matter. What does set2 return? You can prevous bind with a data table if you want, but that re-bind starts over - so just test with set2 since that all that matters here. Commented Feb 11, 2021 at 17:11

2 Answers 2

1

Hi I have looked at your code and i think i know what the problem is.

in the WebUserControl1.ascx.vb you assign a value on Page_load so it works the first time but then on the binding the second time you don't assign a value so you need to add the assignment below WebUserControl1 prerender. Please let me know if it works. Fingers crossed.

Public Class WebUserControl1
    Inherits System.Web.UI.UserControl

    Public Property AssignedValue As String

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        litValue.Text = AssignedValue
    End Sub


    Private Sub WebUserControl1_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
        litValue.Text = AssignedValue
    End Sub
End Class
Sign up to request clarification or add additional context in comments.

3 Comments

Youuuu are the man! That worked! Although I completely do not understand why Load is called AFTER assigning the AssignedValue property when loading the page initially, and BEFORE assigning the property when in a postback. I have read like a dozen asp.net webforms life cycle graphs and none of them seem to explain this. Do you maybe know of a documentation that properly explains or at least documents this behavior? It must have something to do with calling the databind not on page load but afterwards in a click handler, so does the control try to "catch up" the events it has missed (like Load)?
Cool, glad it worked. I hate it when i get stuck on these kind of things. I'm not entirely sure regarding the lifecycle somebody may be able to explain better. What I thought was happening was that page_load wasn't been called on the second databind as it was in the update panel so it needed to be assigned somehow else which is why i suggested the prender event. Glad it worked, sorry i can't explain better.
Well, given that this is a user control, then rendering and load up of course will be different then if this was just a repeater - the issue of course is making sure that the user control is created and takes care of these subtitle issues - if no user control was involved there - then plain jane approach to code and the one time load in on-load with a test for post-back would have worked just fine.
0

I'm not sure if this will help but I had a problem with repeaters before in UpdatePanels and was getting a pull page reload instead of a partial one so losing data.

The repeaters don't seem to handle client ids very well so it caused me problems. I added ClientIDMode="AutoID" to the repeaters attributes which fixed the problem for me.

It may be worth a try. Somebody else may be able to explain this technically better thank me.

1 Comment

As far as I can tell, the page does not do a full reload but does a partial, asynchronous postback (eg. browser doesn't show the loading spinner and F5 doesn't ask for re-submission of form data as it would otherwise). I've set ClientIDMode to AutoID in the repeater with no luck, and then for good measure to literally every single control, also no luck.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.