UpdatePanel, Repeater, DataBinding Problem

.net-2.0asp.netasp.net-ajaxrepeaterupdatepanel

In a user control, I've got a Repeater inside of an UpdatePanel (which id displayed inside of a ModalPopupExtender. The Repeater is databound using an array list of MyDTO objects. There are two buttons for each Item in the list. Upon binding the ImageURL and CommandArgument are set.

This code works fine the first time around but the CommandArgument is wrong thereafter. It seems like the display is updated correctly but the DTO isn't and the CommandArgument sent is the one that has just been removed.

Can anybody spot any problems with the code?

Edit : I've just added a CollapsiblePanelExtender to the code. When I now delete an item and expand the panel, the item that was previously deleted (and gone from the display) has come back. It seems that the Repeater hasn't been rebuilt correctly under the bonnet.

ASCX

<asp:UpdatePanel ID="ViewDataDetail" runat="server" ChildrenAsTriggers="true">
    <Triggers>
        <asp:PostBackTrigger ControlID="ViewDataCloseButton" />
        <asp:AsyncPostBackTrigger ControlID="DataRepeater" />
    </Triggers>
    <ContentTemplate>
        <table width="100%" id="DataResults">
        <asp:Repeater ID="DataRepeater" runat="server" OnItemCommand="DataRepeater_ItemCommand" OnItemDataBound="DataRepeater_ItemDataBound">
        <HeaderTemplate>
            <tr>
            <th><b>Name</b></th>
            <th><b>&nbsp;</b></th>
            </tr>
        </HeaderTemplate>
            <ItemTemplate>
            <tr>
                <td>
                <b><%#((MyDTO)Container.DataItem).Name%></b>
                </td>
                <td>
                <asp:ImageButton CausesValidation="false" ID="DeleteData" CommandName="Delete" runat="server" />
                <asp:ImageButton CausesValidation="false" ID="RunData" CommandName="Run" runat="server" />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                <table>
                    <tr>
                    <td>Description : </td>
                    <td><%#((MyDTO)Container.DataItem).Description%></td>
                    </tr>
                    <tr>
                    <td>Search Text : </td>
                    <td><%#((MyDTO)Container.DataItem).Text%></td>
                    </tr>
                </table>
                </td>
            </tr>
            </ItemTemplate>
        </asp:Repeater>
        </table>
    </ContentTemplate>
</asp:UpdatePanel>

Code-Behind

    public DeleteData DeleteDataDelegate;
    public RetrieveData PopulateDataDelegate;
    public delegate ArrayList RetrieveData();
    public delegate void DeleteData(String sData);


 protected void Page_Load(object sender, EventArgs e)
    {
        //load the initial data..
        if (!Page.IsPostBack)
        {
            if (PopulateDataDelegate != null)
            {
                this.DataRepeater.DataSource = this.PopulateDataDelegate();
                this.DataRepeater.DataBind();
            }
        }
    }

    protected void DataRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
        if (e.CommandName == "Delete")
        {
            if (DeleteDataDelegate != null)
            {
                DeleteDataDelegate((String)e.CommandArgument);
                BindDataToRepeater();
            }
        }
        else if (e.CommandName == "Run")
        {
            String sRunning = (String)e.CommandArgument;
            this.ViewDataModalPopupExtender.Hide();
        }
    }

    protected void DataRepeater_ItemDataBound(object source, RepeaterItemEventArgs e)
    {
        RepeaterItem item = e.Item;
        if (item != null && item.DataItem != null)
        {
            MyDTO oQuery = (MyDTO)item.DataItem;

            ImageButton oDeleteControl = (ImageButton) item.FindControl("DeleteData");
            ImageButton oRunControl = (ImageButton)item.FindControl("RunData");

            if (oDeleteControl != null && oRunControl !=null)
            {
                oRunControl.ImageUrl = "button_expand.gif";
                oRunControl.CommandArgument = "MyID";
                if (oQuery !=null)
                { 
                  //do something
                }
                oDeleteControl.ImageUrl = "btn_remove.gif";
                oDeleteControl.CommandArgument = "MyID";
            }
        }
    }

    public void BindDataToRepeater()
    {
        this.DataRepeater.DataSource = this.PopulateDataDelegate();
        this.DataRepeater.DataBind();
    }

    public void ShowModal(object sender, EventArgs e)
    {
        BindDataToRepeater();
        this.ViewDataModalPopupExtender.Show();
    }

Best Answer

Thanks for reminding me why I stopped using ASP.NET controls. This is the exact type of nightmare that has made too many projects go way over budget and schedule.

My advise to you is to think of the simplest way to implement this. You can try to bend over backwards in order to get this to work the ASP.NET way or take the shortest route. All you're doing is generating HTML, it should never be that difficult.

The most likely cause of your problem is that the ViewState is stored in the page which doesn't get updated on a partial postback. So with every change in the update panel you'll postback the initial viewstate of the page.

Try replacing the repeater with a simple for-loop (and ignore the people who start complaining you shouldn't mix markup and code). Replace your databinding statements with <%= %>. That eliminates the view state all together and should remove any removed row from re-appearing.

Related Topic