ASP.NET - Control Events Not Firing Inside Repeater
Asked Answered
E

5

8

This is a absurdly common issue and having exhausted all of the obvious solutions, I'm hoping SO can offer me some input... I have a UserControl inside a page which contains a repeater housing several controls that cause postback. Trouble is, all of the controls inside of the repeater never hit their event handlers when they postback, but controls outside of the repeater (still in the UC) are correctly handled. I already made sure my controls weren't being regenerated due to a missing if(!IsPostBack) and I verified that Request.Form["__EVENTTARGET"] contained the correct control ID in the Page_Load event. I attempted to reproduce the symptoms in a separate project and it worked as it should.

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="NoteListControl.ascx.cs"
    Inherits="SantekGBS.Web.UserControls.NoteListControl" %>

<asp:UpdatePanel ID="upNotes" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <div class="NoteList" id="divNoteList" runat="server">
            <asp:Repeater ID="repNotes" runat="server">
                <HeaderTemplate>
                    <table width="98%" cellpadding="3" cellspacing="0">
                </HeaderTemplate>
                <ItemTemplate>
                    <tr class="repeaterItemRow">
                        <asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="~/Content/images/DeleteIcon.gif"
                            OnClick="ibRemove_Click" CommandArgument='<%# Container.ItemIndex %>' CommandName='<%# Eval("ID") %>'
                            CausesValidation="false" AlternateText="Delete" />
                        <%# Eval("Text") %></td>
                    </tr>
                </ItemTemplate>
                <FooterTemplate>
                    </table>
                </FooterTemplate>
            </asp:Repeater>
            <asp:PlaceHolder ID="phNoNotes" runat="server" Visible="false">
                <div class="statusMesssage">
                    No notes to display.
                </div>
            </asp:PlaceHolder>
        </div>
    </ContentTemplate>
</asp:UpdatePanel>

public partial class NoteListControl : UserControl
{
    [Ninject.Inject]
    public IUserManager UserManager { get; set; }

    protected List<Note> Notes
    {
        get
        {
            if (ViewState["NoteList"] != null)
                return (List<Note>)ViewState["NoteList"];
            return null;
        }
        set { ViewState["NoteList"] = value; }
    }

    public event EventHandler<NoteEventArgs> NoteAdded;
    public event EventHandler<NoteEventArgs> NoteDeleted;
    public event EventHandler<NoteEventArgs> NoteChanged;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            UtilityManager.FillPriorityListControl(ddlPriority, false);
        }
    }

    protected void ibRemove_Click(object sender, ImageClickEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("ibRemove POSTBACK"); // This is NEVER hit
    }

    public void Fill(List<Note> notes)
    {
        Notes = notes;
        RefreshRepeater();
    }

    private void RefreshRepeater()
    {
        if (Notes != null && Notes.Any())
        {
            var sorted = Notes.OrderByDescending(n => n.Timestamp);
            Notes = new List<Note>();
            Notes.AddRange(sorted);
            repNotes.Visible = true;
            phNoNotes.Visible = false;
            repNotes.DataSource = Notes;
            repNotes.DataBind();
        }
        else
        {
            repNotes.Visible = false;
            phNoNotes.Visible = true;
        }
    }
}

public class NoteEventArgs : EventArgs
{
    public Note Note { get; set; }
    public NoteEventArgs()
    { }
    public NoteEventArgs(Note note)
    {
        this.Note = note;
    }
}

The code is intentionally missing functionality so just disregard that fact.

Emaciation answered 23/11, 2009 at 20:34 Comment(0)
I
4

Your edited code has residual CommandArgument and CommandName properties; are you actually handling the Repeater.ItemCommand event?

If so, and if your page calls the control's Fill method on postbacks, that would explain it.

This classic ASP.NET hair-tearing problem is explained in these posts: A Stumper of an ASP.NET Question and A Stumper of an ASP.NET Question: SOLVED!

The explanation is a little mind-bending, but the crux of it is that Repeater.DataBind interferes with ASP.NET's ability to determine which repeater button caused a postback.

Imitation answered 23/11, 2009 at 21:59 Comment(2)
Although I am using the CommandArgument and CommandName arguments I'm not bubbling events through Repeater.ItemCommand. I'm using the properties to store information which I access in the standard button click event.Emaciation
i think the link should be scottonwriting.net/sowBlog/archive/0000/00/00/162929.aspxForeordain
C
3

I found a missing td-tag in the Itemtemplate, sometimes when DOM is incorrect, the updatapanel do strange things.

Cutinize answered 23/11, 2009 at 20:39 Comment(1)
Good catch, but you can actually disregard that. The markup I'm showing isn't even the same as the production code. I created that <ItemTemplate> just to show the effect. All controls inside the ItemTemplate behave the same way.Emaciation
A
3

Just about EVERY time I run into this problem it's because DataBind() is being called when it shouldn't be. This will kill most events from controls inside a repeater. I see you have an !IsPostBack check in your Page_Load... so that's a start. But try putting a breakpoint on repNotes.DataBind() and see if it's getting called when you don't expect it.

Does it work OK outside of an UpdatePanel?

Alb answered 24/11, 2009 at 8:1 Comment(3)
DataBind() is only being called on the initial page load and after specified control events- none of which are being fired as they should. The UpdatePanel does not seem to be related to the problem. I have another form in my app that also used to work that is exhibiting similar behavior as well, when the form posts back the repeater empties itself as it does here. Very strange behavior.Emaciation
You haven't disabled ViewState for any of these controls have you? You have "another form"... I assume that's a different .aspx page altogether? You don't have an extra form tag in this page?Alb
Bryan's comment helped me: in my case I had EnableViewState="false" on the parent repeater, and that prevented the footer control's postback handler from being fired.Heteronomy
R
1

I ran into the same problem. It happened with me if I've ran the DataBind twice. In other words when I populate the repeater control twice (for any reason) the events wont fire.

I hope that helps.

Roundfaced answered 16/11, 2010 at 20:5 Comment(0)
A
0

After 14 years, I am just answering to help others. Here is the best practice to follow:

Always add the event OnItemCommand and handle all event calls on the basis of CommandName.

For example, if I am making a dropdown, it will go like this:

<asp:Repeater runat="server" ID="rptSchoolOptions" OnItemCommand="rptSchoolOptions_ItemCommand">
                                        <ItemTemplate>
                                            <li class="option">
                                                <asp:LinkButton CommandArgument='<%#Eval("Msid")%>' CommandName="changeSchool" runat="server">
                                                        <i class="fa fa-building"></i>
                                                        <span class="option-text"><%#Eval("SchoolName")%></span>
                                                </asp:LinkButton>

                                            </li>
                                        </ItemTemplate>
                                    </asp:Repeater>

Here, every event will trigger the rptSchoolOptions_ItemCommand function on the backend.

Here is how we can handle it in the backend:

protected void rptSchoolOptions_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            if (e.CommandName == "changeSchool")
            {
                ShowLoading();
                SchoolHelper.setUserSession(Convert.ToInt32(e.CommandArgument.ToString()));
                FillSchools();
                StopLoading();
            }
            else if (e.CommandName == "anyOtherCommand")
            {
                // next funtionality gose here
            }
        }

Here, you can check for the CommandName to determine which LinkButton or trigger was hit to handle as required.

Hope it will help the community.

Adalineadall answered 30/5 at 7:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.