RadGrid Batch Edit Breaks AJAX

1 posts, 0 answers
  1. Cowan
    Cowan avatar
    1 posts
    Member since:
    May 2017

    Posted 02 Aug 2017 Link to this post

    I have been trying to implement a RadGrid with batch edit mode enabled. It is essentially just a grid that makes calls to entity framework to update data in a SQL database. It works fine sometimes, but, usually after I've saved changes a few times, all AJAX calls stop working on the page. I have been trying a lot of different ways of reproducing the bug consistently, but I can't figure out how. I usually just add a few records, and edit a few records, save, then repeat the process several times until eventually it stops working. When I press the button in this state, it will flash the loading symbol for a fraction of a second, but nothing else happens. Normally, the loading symbol shows for a second or two, then the grid and database update. The OnUpdateCommand, OnInsertCommand, and any other commands do not fire when in the erroneous state, and other controls on the page that use AJAX don't work anymore. I can't seem to find any code behind method that gets called upon attempting to call them. The pertinent (I think) code is in the page XAML file GateProduct.aspx, the control XAML file Checklist.ascx that contains the RadGrid, and the codebehind for the control Checklist.ascx.cs.  

    GateProduct.aspx

    <%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" CodeBehind="GateProduct.aspx.cs" Inherits="GatesWebForm.Pages.GateProduct" %>

    <%@ Register Src="~/Controls/Checklist.ascx" TagName="ChecklistPanel" TagPrefix="custom" %>
    <%@ Register Src="~/Controls/Projects.ascx" TagName="ProjectsPanel" TagPrefix="custom" %>
    <%@ Register Src="~/Controls/Documents.ascx" TagName="DocumentsPanel" TagPrefix="custom" %>



    <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
        <link href="Styles/mail.css" rel="stylesheet" />
        <style type="text/css">
            html .RadGrid .rgMasterTable {
                height: auto;
            }

            .subject {
                position: relative;
            }
        </style>


    </asp:Content>
    <asp:Content ID="Content2" ContentPlaceHolderID="FolderContent" runat="server">
        <div style="padding: 5px 5px 5px 5px">
            <asp:Panel runat="server" ID="InfoPanel" BackColor="LightBlue" BorderColor="Black" BorderWidth="2px">
                <asp:Label Text="Product: " runat="server" />
                <asp:Label ID="ProductName" runat="server" Font-Bold="True" /><br />
                <asp:Label runat="server" Text="Version:" />
                <asp:Label runat="server" ID="VersionText" Font-Bold="True" /><br />
                <asp:Label Text="Gate: " runat="server" />
                <asp:Label ID="GateId" runat="server" Font-Bold="True" /><br />
            </asp:Panel>
            
            <asp:HyperLink runat="server" Text="Back To Products" ID="ProductsHyperLink" CssClass="hyperLink"></asp:HyperLink>
        </div>
        <div style="padding: 5px 5px 5px 5px">
            <asp:Button runat="server" ID="DuplicateGateButton" Text="Duplicate this gate"
                OnClick="DuplicateGateButton_OnClick" />
        </div>
    </asp:Content>
    <asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">

        <telerik:RadTabStrip runat="server" RenderMode="Lightweight" ID="TabStrip" MultiPageID="MultiPage" SelectIndex="0">
            <Tabs>
                <telerik:RadTab runat="server" Text="Checklist" />
                <telerik:RadTab runat="server" Text="Projects" />
                <telerik:RadTab runat="server" Text="Documents" />
            </Tabs>
        </telerik:RadTabStrip>
        <telerik:RadMultiPage runat="server" ID="MultiPage" SelectedIndex="0">
            <telerik:RadPageView runat="server" ID="ChecklistPage">
                <custom:ChecklistPanel runat="server" ID="ChecklistPanel" />
            </telerik:RadPageView>
            <telerik:RadPageView runat="server" ID="ProjectsPage">
                <custom:ProjectsPanel runat="server" ID="ProjectsPanel" />
            </telerik:RadPageView>
            <telerik:RadPageView runat="server" ID="DocumentsPage">
                <custom:DocumentsPanel runat="server" ID="DocumentsPanel" />
            </telerik:RadPageView>
        </telerik:RadMultiPage>

        <telerik:RadWindowManager runat="server" ID="RadWindowManager">
        </telerik:RadWindowManager>

        <script type="text/javascript">
            function gatePromptCallBack(newGateId) {
                if (newGateId !== null) {
                    var id = parseInt(getParamValues('id'));
                    var gateId = newGateId.toLowerCase();
                    PageMethods.DuplicateGateProduct(id, gateId);
                }
            }

            function getParamValues(key) {
                var query = window.location.search.substring(1);
                var params = query.split('&');

                for (var i = 0; i < params.length; i++) {
                    var pos = query.indexOf('=');
                    var k = params[i].substring(0, pos);
                    var v = params[i].substring(pos + 1);

                    if (key === k) return v;
                }
                return null;
            }

        </script>

        <telerik:RadAjaxLoadingPanel runat="server" ID="LoadingPanel"></telerik:RadAjaxLoadingPanel>

        <asp:SqlDataSource runat="server" ID="GatesDataSource" ProviderName="System.Data.SqlClient"
            ConnectionString="<%$ ConnectionStrings:GatesConnectionString %>"
            SelectCommand="SELECT * FROM Gates ORDER BY Name" />
    </asp:Content>

    ------

    This is the control Checklist.ascx that has the RadGrid: 

     

     

    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Checklist.ascx.cs" Inherits="GatesWebForm.Controls.Checklist" %>

    <%@ Register Src="~/Controls/StatusMessage.ascx" TagName="StatusMessage" TagPrefix="custom" %>



    <input id="ClientAreUnsavedChanges" type="hidden" runat="server"/>

    <telerik:RadAjaxManagerProxy runat="server" ID="RadAjaxManager">
        <AjaxSettings>
            <telerik:AjaxSetting AjaxControlID="ChecklistGrid" EventName="">
                <UpdatedControls>
                    <telerik:AjaxUpdatedControl ControlID="ChecklistPanel" LoadingPanelID="LoadingPanel"/>
                    <telerik:AjaxUpdatedControl ControlID="StatusMessage"/>
                    <telerik:AjaxUpdatedControl ControlID="UnsavedChangesScript"/>
                </UpdatedControls>
            </telerik:AjaxSetting>
            <telerik:AjaxSetting AjaxControlID="NoChecklistPanel">
                <UpdatedControls>
                    <telerik:AjaxUpdatedControl ControlID="ChecklistPanel" LoadingPanelID="LoadingPanel"/>
                    <telerik:AjaxUpdatedControl ControlID="NoChecklistPanel" LoadingPanelID="LoadingPanel"/>
                </UpdatedControls>
            </telerik:AjaxSetting>
            <telerik:AjaxSetting AjaxControlID="CreateEmptyChecklistButton">
                <UpdatedControls>
                    <telerik:AjaxUpdatedControl ControlID="ChecklistPanel" LoadingPanelID="LoadingPanel"/>
                    <telerik:AjaxUpdatedControl ControlID="NoChecklistPanel" LoadingPanelID="LoadingPanel"/>
                </UpdatedControls>
            </telerik:AjaxSetting>
            <telerik:AjaxSetting AjaxControlID="CreateDefaultChecklistButton">
                <UpdatedControls>
                    <telerik:AjaxUpdatedControl ControlID="ChecklistPanel" LoadingPanelID="LoadingPanel"/>
                    <telerik:AjaxUpdatedControl ControlID="NoChecklistPanel" LoadingPanelID="LoadingPanel"/>
                </UpdatedControls>
            </telerik:AjaxSetting>
            <telerik:AjaxSetting AjaxControlID="DeleteSelectedButton">
                <UpdatedControls>
                    <telerik:AjaxUpdatedControl ControlID="ChecklistPanel" LoadingPanelID="LoadingPanel"/>
                    <telerik:AjaxUpdatedControl ControlID="StatusMessage"/>
                </UpdatedControls>
            </telerik:AjaxSetting>
            <telerik:AjaxSetting AjaxControlID="DeleteChecklistButton">
                <UpdatedControls>
                    <telerik:AjaxUpdatedControl ControlID="ChecklistPanel" LoadingPanelID="LoadingPanel"/>
                    <telerik:AjaxUpdatedControl ControlID="NoChecklistPanel"/>
                </UpdatedControls>
            </telerik:AjaxSetting>
        </AjaxSettings>
    </telerik:RadAjaxManagerProxy>

    <telerik:RadScriptBlock runat="server" ID="UnsavedChangesScript">
        <script type="text/javascript">
            function batchEditCellValueChanged() {
                window.onbeforeunload = function () {
                    return true;
                }
            }

            function serverDataBound() {
                window.onbeforeunload = null;
            }
        </script>
    </telerik:RadScriptBlock>

    <h1>Checklist</h1>

    <asp:Panel runat="server" ID="ChecklistPanel">
        <telerik:RadGrid ID="ChecklistGrid" runat="server" AllowPaging="true" DataSourceID="ChecklistItemsDataSource"
                         GridLines="None" Width="95%" AutoGenerateColumns="false" OnUpdateCommand="ChecklistGrid_UpdateCommand"
                         OnDeleteCommand="ChecklistGrid_OnDeleteCommand" OnInsertCommand="ChecklistGrid_OnInsertCommand"
                         AllowMultiRowSelection="True" AllowSorting="True" OnDataBound="ChecklistGrid_OnDataBound"
            OnItemCommand="ChecklistGrid_OnItemCommand" OnCallingDataMethods="ChecklistGrid_OnCallingDataMethods">
            <MasterTableView DataKeyNames="ChecklistItemId" CommandItemDisplay="Top" EditMode="Batch">
                <BatchEditingSettings OpenEditingEvent="Click"></BatchEditingSettings>
                <CommandItemSettings ShowSaveChangesButton="True"></CommandItemSettings>
                <Columns>
                    <telerik:GridTemplateColumn DataField="Question" HeaderText="Question"
                                                SortExpression="Question" Resizable="True" UniqueName="Question">
                        <ItemTemplate>
                            <%# DataBinder.Eval(Container.DataItem, "Question") %>
                        </ItemTemplate>
                        <EditItemTemplate>
                            <asp:TextBox runat="server" Text='<%# Bind("Question") %>' TextMode="MultiLine" ID="QuestionTextBox"/>
                        </EditItemTemplate>
                    </telerik:GridTemplateColumn>
                    <telerik:GridTemplateColumn DataField="Comment" HeaderText="Comment"
                                                SortExpression="Comment" Resizable="True">
                        <ItemTemplate>
                            <%# DataBinder.Eval(Container.DataItem, "Comment") %>
                        </ItemTemplate>
                        <EditItemTemplate>
                            <asp:TextBox runat="server" Text='<%# Bind("Comment") %>' TextMode="MultiLine" ID="CommentTextBox"/>
                        </EditItemTemplate>
                    </telerik:GridTemplateColumn>
                    <telerik:GridDateTimeColumn DataField="DateAnswered" HeaderText="Date Answered"
                                                DataFormatString="{0:d}" PickerType="DatePicker"
                                                ConvertEmptyStringToNull="True" ReadOnly="True"
                                                Resizable="True"/>
                </Columns>
            </MasterTableView>
            <ClientSettings EnableAlternatingItems="False">
                <Selecting AllowRowSelect="True" EnableDragToSelectRows="True"/>
                <Resizing AllowColumnResize="True" AllowRowResize="True"/>
                <ClientEvents OnBatchEditCellValueChanged="batchEditCellValueChanged"/>
            </ClientSettings>
        </telerik:RadGrid>

        <asp:Button runat="server" ID="DeleteSelectedButton" Text="Delete selected items"
                    OnClick="DeleteSelectedButton_OnClick"
                    OnClientClick="javascript:if (!confirm('Delete all selected?')) return false;"/>
        <asp:Button runat="server" ID="DeleteChecklistButton" Text="Delete entire checklist"
                    OnClick="DeleteChecklistButton_OnClick"
                    OnClientClick="javascript:if (!confirm('Delete entire checklist?')) return false;"/>
    </asp:Panel>


    <asp:Panel runat="server" ID="NoChecklistPanel">
        <asp:Label runat="server" Text="No checklist found."/>
        <br/>
        <asp:Button runat="server" ID="CreateEmptyChecklistButton" Text="Create Empty Checklist"
                    OnClick="CreateEmptyChecklistButton_OnClick"/>
        <asp:Button runat="server" ID="CreateDefaultChecklistButton" Text="Create Default Checklist"
                    OnClick="CreateDefaultChecklistButton_OnClick"/>
    </asp:Panel>


    <custom:StatusMessage runat="server" ID="StatusMessage" TargetControlId="ChecklistGrid"/>

    <asp:SqlDataSource ID="ChecklistItemsDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:GatesConnectionString %>"
                       ProviderName="System.Data.SqlClient"
                       SelectCommand="SELECT ChecklistItems.*, Answer, 
                                QuestionTypes.Name AS QuestionTypeName,
                                People.Name AS PersonName, 
                                People.Username AS PersonUsername,
                                Departments.Name AS DepartmentName
                                FROM ChecklistItems 
                                LEFT JOIN ChecklistAnswers
                                ON Answer_AnswerId = AnswerId
                                LEFT JOIN QuestionTypes 
                                ON Type_QuestionTypeId = QuestionTypeId
                                LEFT JOIN People 
                                ON PersonId = AssignedTo_PersonId
                                LEFT JOIN Departments
                                ON Department_DepartmentId = DepartmentId
                                WHERE Checklist_ChecklistId = @GateProductId">
        <SelectParameters>
            <asp:QueryStringParameter Name="GateProductId" QueryStringField="id"/>
        </SelectParameters>
    </asp:SqlDataSource>
    <asp:SqlDataSource ID="AnswersDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:GatesConnectionString %>"
                       ProviderName="System.Data.SqlClient" SelectCommand="SELECT * FROM ChecklistAnswers ORDER BY Answer"/>
    <asp:SqlDataSource runat="server" ID="PeopleDataSource"
                       ConnectionString="<%$ ConnectionStrings:GatesConnectionString %>"
                       ProviderName="System.Data.SqlClient"
                       SelectCommand="SELECT NULL AS PersonId, NULL AS Name
                    UNION 
                    SELECT PersonId, Name FROM People
                    ORDER BY Name"/>

    <asp:ObjectDataSource runat="server" ID="EmployeeDataSource" SelectMethod="GetActiveDirectoryUsers"
                          TypeName="GatesWebForm.Authenticator">
    </asp:ObjectDataSource>

    <asp:SqlDataSource runat="server" ID="QuestionTypesDataSource" ConnectionString="<%$ ConnectionStrings:GatesConnectionString %>"
                       ProviderName="System.Data.SqlClient" SelectCommand="SELECT NULL AS QuestionTypeId, NULL AS Name UNION SELECT QuestionTypeId, Name FROM QuestionTypes ORDER BY Name"/>

    <asp:SqlDataSource runat="server" ID="DepartmentsDataSource" ConnectionString="<%$ ConnectionStrings:GatesConnectionString %>"
                       ProviderName="System.Data.SqlClient" SelectCommand="SELECT NULL AS DepartmentId, NULL AS Name UNION SELECT DepartmentId, Name FROM Departments ORDER BY Name"/>

     

    ----------

    This is the code behind Checklist.ascx.cs:

     

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using GatesDataEntry;
    using GatesDataEntry.GateModels;
    using GatesWebForm.Services;
    using Microsoft.TeamFoundation.Common;
    using Telerik.Web.UI;

    namespace GatesWebForm.Controls
    {
        public partial class Checklist : UserControl
        {
            private readonly GateContext mContext = new GateContext();
            private readonly Authenticator mAuthenticator = new Authenticator();

            private RadWindowManager mWindowManager;

            private ChecklistDataService mChecklistDataService;

            public bool AreUnsavedChanges
            {
                get => bool.Parse(ClientAreUnsavedChanges.Value);
            }

            protected void Page_Load(object sender, EventArgs e)
            {
                var id = int.Parse(Request.QueryString["id"], CultureInfo.InvariantCulture);
                if (mContext.Checklists.Any(c => c.ChecklistId == id))
                {
                    ChecklistPanel.Visible = true;
                    NoChecklistPanel.Visible = false;
                }
                else
                {
                    ChecklistPanel.Visible = false;
                    NoChecklistPanel.Visible = true;
                }

                mChecklistDataService = new ChecklistDataService(id, mContext);

                mWindowManager = Parent.FindControl("RadWindowManager") as RadWindowManager;
            }

            protected void ChecklistGrid_UpdateCommand(object sender, GridCommandEventArgs e)
            {
                if (!mAuthenticator.IsEditor())
                {
                    mWindowManager.RadAlert("You do not have editor permissions.", 400, 100, "Need Permissions", null);
                    return;
                }


                if (e.CommandArgument is GridBatchEditingEventArgument)
                    try
                    {
                        UpdateItem(e);
                    }
                    catch (Exception ex)
                    {
                        e.Canceled = true;
                    }
            }

            private void UpdateItem(GridCommandEventArgs e)
            {
                if (!(e.CommandArgument is GridBatchEditingEventArgument)) return;

                var editedItem = e.Item as GridEditableItem;
                var commandArgument = (GridBatchEditingEventArgument) e.CommandArgument;
                var newValues = commandArgument.NewValues;

                var tableView = commandArgument.OwnerTableView;
                tableView.ExtractValuesFromItem(newValues, editedItem);

                var id = (int) editedItem.OwnerTableView.DataKeyValues[editedItem.ItemIndex]["ChecklistItemId"];
                var question = (string) newValues["Question"];
                var comment = (string) newValues["Comment"]; 

                var answer = mContext.ChecklistAnswers.Single(a => a.Answer == "Done"); 

                mChecklistDataService.UpdateChecklistItem(id, question, answer, comment, null, null, null);
            }

            protected void ChecklistGrid_OnDeleteCommand(object sender, GridCommandEventArgs e)
            {
                if (!mAuthenticator.IsEditor())
                {
                    mWindowManager.RadAlert("You do not have editor permissions.", 400, 100, "Need Permissions", null);
                    return;
                }
                try
                {
                    var id = (int) e.Item.OwnerTableView.DataKeyValues[e.Item.ItemIndex]["ChecklistItemId"];
                    mChecklistDataService.DeleteChecklistItem(id);
                }
                catch (Exception)
                {
                    e.Canceled = true;
                }

                ChecklistGrid.Rebind();
            }

            protected void ChecklistGrid_OnInsertCommand(object sender, GridCommandEventArgs e)
            {
                if (!mAuthenticator.IsEditor())
                {
                    mWindowManager.RadAlert("You do not have editor permissions.", 400, 100, "Need Permissions", null);
                    return;
                }

                try
                {
                    var commandArgument = e.CommandArgument as GridBatchEditingEventArgument;
                    var inputValues = commandArgument.NewValues;
                    var question = (string) inputValues["Question"];
                    var comment = (string) inputValues["Comment"]; 

                    var answer = mContext.ChecklistAnswers.Single(a => a.Answer == "not done");

                    mChecklistDataService.InsertChecklistItem(question, answer, comment, null, null, null);
                    StatusMessage.DisplayMessage(false, "Successfully inserted checklist item.");
                }
                catch (Exception ex)
                {
                    e.Canceled = true;
                }
            }

            protected void CreateEmptyChecklistButton_OnClick(object sender, EventArgs e)
            {
                if (!mAuthenticator.IsEditor())
                {
                    mWindowManager.RadAlert("You do not have editor permissions.", 400, 100, "Need Permissions", null);
                    return;
                }

                mChecklistDataService.CreateEmptyChecklist();
                ChecklistGrid.Rebind(); 
                NoChecklistPanel.Visible = false;
                ChecklistPanel.Visible = true;
            }

            protected void CreateDefaultChecklistButton_OnClick(object sender, EventArgs e)
            {
                if (!mAuthenticator.IsEditor())
                {
                    mWindowManager.RadAlert("You do not have editor permissions.", 400, 100, "Need Permissions", null);
                    return;
                }

                mChecklistDataService.CreateDefaultChecklist();
                ChecklistGrid.Rebind();
                NoChecklistPanel.Visible = false;
                ChecklistPanel.Visible = true;
            }
            
            protected void DeleteSelectedButton_OnClick(object sender, EventArgs e)
            {
                if (!mAuthenticator.IsEditor())
                {
                    mWindowManager.RadAlert("You do not have editor permissions.", 400, 100, "Need Permissions", null);
                    return;
                }
                try
                {
                    if (ChecklistGrid.SelectedIndexes.Count == 0)
                        return;
                    var ids = (from GridDataItem item in ChecklistGrid.SelectedItems
                               select (int) item.OwnerTableView.DataKeyValues[item.ItemIndex]["ChecklistItemId"]).ToList();
                    mChecklistDataService.DeleteChecklistItemsRange(ids);

                    StatusMessage.DisplayMessage(false, "Successfully deleted checklist items.");
                }
                catch (Exception ex)
                {
                    StatusMessage.DisplayMessage(true, "Failed to delete checklist items.");
                }

                ChecklistGrid.Rebind();
            }

            protected void DeleteChecklistButton_OnClick(object sender, EventArgs e)
            {
                mChecklistDataService.DeleteChecklist(); 

                ChecklistPanel.Visible = false;
                NoChecklistPanel.Visible = true;
            }
            
            protected void ChecklistGrid_OnDataBound(object sender, EventArgs e)
            {
                ScriptManager.RegisterStartupScript(Page, Page.GetType(), "setUnsavedChangesFalse", "serverDataBound();", true);
            }

            protected void ChecklistGrid_OnItemCommand(object sender, GridCommandEventArgs e)
            {
            }

            protected void ChecklistGrid_OnCallingDataMethods(object sender, CallingDataMethodsEventArgs e)
            {
                throw new NotImplementedException();
            }
        }
    }

Back to Top