C# ASP.NET CheckBox_OnCheckedChanged not firing as

2019-07-25 11:51发布

问题:

I have an issue with both Checkbox_OnCheckedChanged and Dropdownlist_OnSelectedIndexChanged events not triggering the relevant functions in my code behind.

Both Controls are bound to values in a GridView. On the first OnCheckedChanged or OnSelectedIndexChanged event raised from the UI the functions in the code behind fire without error, however if I refresh my UpdatePanel, for example by changing the date range of the data inside the GridView and therefore loading more or less records, the OnCheckedChanged and OnSelectedIndexChanged functions are no longer called, however a PostBack occurs.

I believe that the functions are not being called as the function that rebinds the GridView is called instead:

 private void report_DateChanged(object sender, EventArgs e)
 {
        // Bind GridView here..
 }

however I cannot figure out why this happens.

I have a MasterPage:

namespace ReportingSystemV2.Reporting
{
public partial class Reporting : System.Web.UI.MasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Attach to DateChanged Event on DateChange UserControl to Function
        DateRangeSelect.dateChanged += new DateRangeSelect.dateChangedEventHandler(dtRgSel_dateChanged);
    }

    // Declare an event for the content pages
    public event EventHandler reportDateChanged;

    // Called on a date change event
    protected void dtRgSel_dateChanged(object sender, DateChangedEventArgs e)
    {
        // Raise the event for content pages
        if (reportDateChanged != null)
            reportDateChanged(this, EventArgs.Empty);
    }
}

This MasterPage has a Control for selecting my date range..

The main section of code for my control ascx code is:

<%--UpdatePanel to trigger datechange--%>
<asp:UpdatePanel runat="server" ID="UpdatePanelDateChanged" OnLoad="UpdatePanelDateChanged_Load" >
</asp:UpdatePanel>

<%--When the date changes in javascript a postback is called in the updatepanel--%>
__doPostBack('<%=UpdatePanelDateChanged.ClientID %>', null);

And the the main section of code behind for this control is:

// Declare a delegate
public delegate void dateChangedEventHandler(object sender, DateChangedEventArgs e);

// Declare an event for any pages that have the control
public event dateChangedEventHandler dateChanged;

protected virtual void OnDateChanged(DateChangedEventArgs e)
{
    dateChangedEventHandler handler = dateChanged;

    // Raise the event
    if (handler != null)
        handler(this, e);
}

protected void UpdatePanelDateChanged_Load(object sender, EventArgs e)
{
   // Trigger the controls public event
   OnDateChanged(new DateChangedEventArgs(DateTime.Parse(dates[0]), DateTime.Parse(dates[1])));

}

In my content page my aspx code is:

<%@ Page Title="Downtime" Language="C#" MasterPageFile="~/Reporting/Reporting.Master" AutoEventWireup="true" CodeBehind="GensetDowntime.aspx.cs" Inherits="ReportingSystemV2.Reporting.GensetDowntime" %>

<%@ MasterType VirtualPath="~/Reporting/Reporting.Master" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ReportingSubContent" runat="server">
<div class="container-fluid">
    <asp:UpdatePanel ID="updPanelDowntime" runat="server">
        <ContentTemplate>
            <div class="row">
                <div id="downtimeDiv" runat="server">
                    <asp:GridView ID="gridDowntime" runat="server" AutoGenerateColumns="False" GridLines="None" CssClass="table table-striped table-condensed"
                        OnRowDataBound="gridDowntime_RowDataBound"
                        OnSelectedIndexChanged="gridDowntime_SelectedIndexChanged"
                        DataKeyNames="ID,ID_Location,iddown,idup,dtdown,dtup,isexempt" EmptyDataText="No exempts in the selected period.">
                        <Columns>
                            <asp:TemplateField>
                                <ItemTemplate>
                            <asp:TemplateField HeaderText="Exempt?">
                                <ItemTemplate>
                                    <asp:DropDownList ID="ddlDowntimeExempt" AutoPostBack="true" runat="server"
                                        OnSelectedIndexChanged="ddlDowntimeExempt_SelectedIndexChanged">
                                        <asp:ListItem Value="-1">Unverified</asp:ListItem>
                                        <asp:ListItem Value="1">Yes</asp:ListItem>
                                        <asp:ListItem Value="0">No</asp:ListItem>
                                    </asp:DropDownList>
                                    <asp:Label ID="lblDowntimeExempt" runat="server" Text='<%#DataBinder.Eval(Container.DataItem,"isexempt")%>' Visible="false"></asp:Label>
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField HeaderText="Exclude?">
                                <ItemTemplate>
                                    <asp:CheckBox ID="chkDowntimeExclude" runat="server" Checked='<%#Convert.ToBoolean(Eval("ISEXCLUDED")) %>' OnCheckedChanged="chkDowntimeExclude_CheckedChanged" AutoPostBack="true"/>
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:CommandField ShowSelectButton="True" SelectText="Details" />
                        </Columns>

                    </asp:GridView>
                </div>
            </div>
        </ContentTemplate>
    </asp:UpdatePanel>
</div>
</asp:Content>

And finally my code behind for my content page is:

    protected void Page_PreInit(object sender, EventArgs e)
    {
        // Attach to UserControl Event on the MasterPage
        Master.reportDateChanged += new EventHandler(report_DateChanged);
    }

    // If the user changes the date lets update the table
    private void report_DateChanged(object sender, EventArgs e)
    {
        // Bind the gridview
    }

    // Function to be called when the ddl selectedindex is changed, only called on initial page load
    protected void ddlDowntimeExempt_SelectedIndexChanged(object sender, EventArgs e)
    {
        // Applies the values selected in the exempt DDL to the database value
    }

    // function to be called when the checkbox checked state is change, again only called on the initial page loading - not after a postback
    protected void chkDowntimeExclude_CheckedChanged(object sender, EventArgs e)
    {
        // When the Exclude checkbox is changed, update the Db
    }

The code above shows the control that uses javascript to trigger a PostBack on an UpdatePanel, which triggers a public event in the Control. The MasterPage has a function which is attached to the Control Event, this MasterPage functions updates a few values and triggers a new Event which is accessable to my ContentPage. The ContentPage attaches a function to this MasterPage Event and when the DateRange is changed it will load the data for the GridView and bind it.

回答1:

Master pages append extra names at the beginning of controls in "child" pages. Most likely you are expecting the dropdown to have a name but it will have a different longer one like ctrl1$something$dropdown.

Check the ida using inspect in Chrome or dev tools to confirm that this is your problem first.



回答2:

I think you're missing async postback triggers. When an update panel partially posts back, it sends back the whole page, does the processing, and then returns only the portion that changed. Probably in that process, slight ID changes have taken place and then there are missed registrations. The report_DateChanged is fired most probably because it is the first control on the page that implements IPostBackEventHandler (because the postback on the checkbox and dropdown don't work any more)

To resolve that, explicitly add each control that should do an async postback to the update panel's triggers. like this:

protected void gridDowntime_RowDataBound(object sender, GridViewRowEventArgs e)  
{  
    DropDownList ddl = e.Row.FindControl("ddlDowntimeExempt") as DropDownList;  
    CheckBox cb = e.Row.FindControl("chkDowntimeExclude") as CheckBox;  
    ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(ddl);  
    ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(cb);  
}  


回答3:

Problem solved, by modifying the code in my DateRangeControl the UpdatePanel is no longer being triggered on all PostBacks, only those where it is called by __doPostBack('<%=UpdatePanelDateChanged.ClientID %>', null); in my Javascript.

protected void UpdatePanelDateChanged_Load(object sender, EventArgs e)
{
    if (Request["__EVENTTARGET"] == UpdatePanelDateChanged.ClientID)
    {

        //Trigger Event
        OnDateChanged(new DateChangedEventArgs(DateTime.Parse(dates[0]), DateTime.Parse(dates[1])));

    }
}

Solution reference: http://encosia.com/are-you-making-these-3-common-aspnet-ajax-mistakes/