Button in GridView in UpdatePanel Throws "Invalid postback or callback argument" on Click

811 views Asked by At

I'm trying to make a jQuery confirm dialog call a web method. The dialog is called when the delete button in a GridView in an UpdatePanel is clicked.

However, when I click on the button, an error "Invalid postback or callback argument." I searched through some of the questions/answers here and tried overriding the Render event to register the UpdatePanel.

Here's my aspx page:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="DoPostBack._Default" %>

<asp:Content ID="conStyles" runat="server" ContentPlaceHolderID="cphStyles">
</asp:Content>
<asp:Content ID="conMain" runat="server" ContentPlaceHolderID="cphMain">
    <asp:UpdatePanel ID="upMovies" runat="server" UpdateMode="Conditional" onload="upMovies_Load">
        <ContentTemplate>
            <asp:GridView ID="gvItems" runat="server" CssClass="tbl-movies" AutoGenerateColumns="False">
                <Columns>
                    <asp:BoundField DataField="Title" HeaderText="Title" HeaderStyle-CssClass="col-title-header" ItemStyle-CssClass="col-title"/>
                    <asp:BoundField DataField="Director" HeaderText="Director" HeaderStyle-CssClass="col-director-header" ItemStyle-CssClass="col-director" />
                    <asp:BoundField DataField="Year" HeaderText="Year" HeaderStyle-CssClass="col-year-header" ItemStyle-CssClass="col-year" />
                    <asp:TemplateField ItemStyle-HorizontalAlign="Left" ItemStyle-CssClass="table-actions">
                        <ItemTemplate>
                            <asp:ImageButton ID="btnEdit" ImageUrl="Images/edit.png" runat="server"
                                Text="Edit" UseSubmitBehavior="False" />
                            <asp:ImageButton ID="btnDelete" ImageUrl="Images/delete.png" runat="server"
                                Text="Delete" UseSubmitBehavior="False" CssClass="btn-delete-movie" />
                            <asp:HiddenField ID="hfMovieId" runat="server" Value='<%# Eval("Id") %>' />
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
        </ContentTemplate>
    </asp:UpdatePanel>
    <div id="confirmDelete" class="popup popup-confirm">
        <div class="popup-title">
            <h4>Delete Movie</h4>
        </div>
        <div class="popup-content">
            <div class="confirm-message">
            </div>
            <div class="buttons center">
                <input id="btnDeleteConfirm" type="button" value="OK" class="button btn-confirm" />
                <input id="btnDeleteCancel" type="button" value="Cancel" class="button btn-delete-cancel btn-close-popup" />
            </div>
        </div>
    </div>
</asp:Content>
<asp:Content ID="conScripts" runat="server" ContentPlaceHolderID="cphScripts">
    <script src="Scripts/site.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var btnDelete = $('.btn-delete-movie');
            btnDelete.on('click', function (e) {
                e.preventDefault();

                var row = $(this).closest('tr'),
                    title = row.find('.col-title').text(),
                    movieId = parseInt(row.find('input[type=hidden]').val());

                showConfirmPopUp('confirmDelete',
                    'Are you sure you want to delete the movie "' + title + '"?',
                    function () { deleteMovie(movieId); }, //call the DeleteMovie web method
                    function () { }); //do nothing else
            });
        });

        function deleteMovie(id) {
            $.ajax({
                type: 'POST',
                contentType: 'application/json',
                data: '{"id":' + id + '}',
                url: 'Default.aspx/DeleteMovie',
                dataType: 'json',
                success: function (data) {
                    __doPostBack('<%= upMovies.ClientID %>', '');
                    closePopUp('confirmDelete');
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    showError(jqXHR, textStatus, errorThrown);
                }
            });
        }
    </script>
</asp:Content>

Code-behind:

public partial class _Default : System.Web.UI.Page
{
    #region Events
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            PopulateMovies();
        }
    }

    protected override void Render(HtmlTextWriter writer)
    {
        ClientScript.RegisterForEventValidation(upMovies.UniqueID);

        foreach (GridViewRow row in gvItems.Rows)
        {
            var btnDelete = row.FindControl("btnDelete");
            var btnEdit = row.FindControl("btnEdit");
            ClientScript.RegisterForEventValidation(btnDelete.UniqueID);
            ClientScript.RegisterForEventValidation(btnEdit.UniqueID);
        }

        base.Render(writer);
    }

    protected void upMovies_Load(object sender, EventArgs e)
    {
        PopulateMovies();
    }
    #endregion

    #region Private Methods
    private void PopulateMovies()
    {
        var data = from m in Movie.GetAll()
                   orderby m.Year descending, m.Title ascending
                   select m;

        gvItems.DataSource = data;
        gvItems.DataBind();
    }
    #endregion

    #region Web Methods
    [WebMethod]
    public static object DeleteMovie(int id)
    {
        Movie.Delete(id);
        return UpdateItems();
    }
    #endregion
}

I'm using the jQuery approach because I don't want to use the ModalPopupExtender. I don't want to set EnableEventValidation to false either.

Also, why is the upMovies_Load called when I click on the delete button? Shouldn't it only be called when the ok button of the confirm dialog is clicked?

I'm kind of a beginner, help would be greatly appreciated.

Thank you :)

1

There are 1 answers

0
dork On BEST ANSWER

Okay, you have to rebind the JavaScript again via

Sys.WebForms.PageRequestManager.GetInstance().add_endRequest(function(){
    //$(document).ready() code here
});