ASP.NET的复选框在取消勾选时不会触发CheckedChanged事件

32

我在一个ASP.NET内容表单上有一个复选框,代码如下:

<asp:CheckBox runat="server" ID="chkTest" AutoPostBack="true" OnCheckedChanged="chkTest_CheckedChanged" />

在我的代码后台中,我有以下方法:

protected void chkTest_CheckedChanged(object sender, EventArgs e)
{
}
当我在浏览器中加载页面并单击复选框时,它变为选中状态,页面进行了提交(postback),我可以看到chkTest_CheckedChanged被调用。当我再次单击复选框时,它变为未选中状态,页面进行了提交,但是chkTest_CheckedChanged没有被调用。这个过程可以重复,因此一旦复选框取消选中,再次选中将触发事件。
我已经在Web.Config中禁用了View State,启用View State会使这个问题消失。有什么方法可以在View State保持禁用的情况下实现可靠的事件触发?
更新:如果我在服务器标记上设置Checked="true",情况就会反转,当取消选中复选框时,事件会被触发,而选中时不会。
更新2:我在页面中覆盖了OnLoadComplete,从那里我可以确认Request.Form["__EVENTTARGET"]正确设置为我的复选框的ID。

2
这也发生在我身上,为什么会这样?有任何信息吗?有没有任何希望(不会让我被碾过的)? - Ayyash
如果您能够发布Page_Load事件的代码,将会很有帮助。 - Waqas
Page_Load事件中没有任何内容。所有的代码都在原始帖子中。 - Matt
10个回答

33

要触发 CheckedChanged 事件,请设置 CheckBox 的以下属性,AutoPostBack 属性应为 true,并且应该有一个默认值,可以是 checked false 或 true。

AutoPostBack="true" Checked="false"

6
被采纳的答案对于这个简单的问题来说过于复杂了。这个答案应该被采纳。 - Matheus Rocha
我完全同意@MatheusRocha的观点。我对被接受的答案感到非常沮丧,肯定不会尝试它。这个答案真的让我避免了改变我的设计。 - Unbound
好的,我同意这应该是被接受的答案。对我来说肯定有效! - Andrew Fielden
这应该是针对此情况的被接受答案。 - John Waclawski

19

实现一个自定义的CheckBox,将Checked属性存储在ControlState而不是ViewState中,即使CheckBox具有AutoPostBack=false也可以解决该问题。

与ViewState不同,ControlState无法禁用,并且可用于存储对控件行为至关重要的数据。

我现在没有Visual Studio环境来测试,但应该看起来像这样:

public class MyCheckBox : CheckBox
{
    private bool _checked;

    public override bool Checked { get { return _checked; } set { _checked = value; } }

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        //You must tell the page that you use ControlState.
        Page.RegisterRequiresControlState(this);
    }

    protected override object SaveControlState()
    {
        //You save the base's control state, and add your property.
        object obj = base.SaveControlState();

        return new Pair (obj, _checked);
    }

    protected override void LoadControlState(object state)
    {
        if (state != null)
        {
            //Take the property back.
            Pair p = state as Pair;
            if (p != null)
            {
                base.LoadControlState(p.First);
                _checked = (bool)p.Second;
            }
            else
            {
                base.LoadControlState(state);
            }
        }
    }
}

更多信息请点击此处


谢谢,这就像魔法一样好用。我简直不敢相信在我使用 .Net 工作的所有时间里,直到现在我才遇到这个问题。这也适用于动态创建的复选框,只需将它们注册为“MyCheckBox”实例,而不是标准实例,你就可以继续前进了。 - pharophy
感谢你。为什么复选框不能直接工作,我不知道。 - Duncan Howe

9

因为禁用了视图状态,所以它不会触发。服务器代码不知道复选框之前是否被选中,因此不知道状态是否更改。就 asp.net 而言,在 postback 之前复选框控件未被选中,在 postback 后仍未被选中,这也解释了当设置 Checked="true" 时看到的反向行为。


我一年后回到这个问题,所以我记不清当时我的想法是什么了,但你说得对,页面生命周期确实会导致这种效应。我认为可能是因为__EVENTTARGET被设置为我的复选框,我希望ASP.NET聪明到足以意识到它已经改变了。 - Matt

6

虽然这是一个旧文章,但我仍希望分享我的简单解决方案,以帮助其他搜索这个问题的人。

解决方案很简单:开启自动回发

        <asp:CheckBox id="checkbox1" runat="server"
                AutoPostBack="True" //<<<<------
                Text="checkbox"
                OnCheckedChanged="knowJobCBOX_CheckedChanged"/>

6
我不确定,但我猜我的解决方案仅适用于.NET Framework 4.0:
使用“ViewStateMode =“Disabled””而不是“EnableViewState =“false””来禁用视图状态。这将导致相同的行为,只是您可以保存本地视图状态。
因此,在复选框上设置属性“ViewStateMode =“Enabled””,问题就解决了,而无需实现自定义复选框。

1

我想整理一下代码,所以花了一点时间来测试解决方案。

joshb给出的关于CheckBox行为的解释是正确的。

由于我不知道去年我是如何解决这个问题的,甚至不确定我是否解决了它(我不能记得当时正在做什么来进行检查),因此我提供了一个简单的解决方案/变通方法。

public class CheckBox2 : CheckBox
{
    protected override bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
    {
        bool isEventTarget = postCollection["__EVENTTARGET"] == UniqueID;
        bool hasChanged = base.LoadPostData(postDataKey, postCollection);
        hasChanged = hasChanged || isEventTarget;
        return hasChanged;
    }
}

如果您现在在页面中注册CheckBox2并在标准复选框的位置使用它,那么当ViewState禁用且AutoPostBack启用时,您将获得所期望的CheckedChanged事件。
这种工作方式允许普通的复选框进行验证和更改检查,但然后执行额外的检查以查看它是否是导致回发的事件的目标。如果它是目标,则返回true以告诉框架引发CheckedChanged事件。
编辑:请注意,这仅解决了复选框上的AutoPostBack问题。如果从其他任何地方(例如按钮)调用PostBack,则CheckedChanged事件仍会出现观察到的问题。

当LoadPostData未调用时,以下内容可能有所帮助:https://dev59.com/6U7Sa4cB1Zd3GeqP7_Tm - sll

0
此外:检查JavaScript控制台中是否有任何错误
我遇到了与OP描述的完全相同的问题,只是它只发生在Safari中(checkbox在Chrome和Firefox中运行良好)。在检查JavaScript控制台时,我发现一个由于格式不正确的jQuery选择器引起的错误。
在我的情况下,我使用了$('a[id*=lbView'),缺少一个闭合的]。这在Safari中引发了错误,但令人惊讶的是,在Chrome和Firefox中没有出现错误。

0

我曾经遇到过同样的问题。我花了很多时间才最终解决了它。

在我的情况下,复选框默认是禁用的:

<asp:CheckBox ID="chkActive" runat="server" Enabled="false"/>

原来当控件禁用或不可见时,ViewState不会被加载。因此,请移除 Enabled="false"Visible="false",然后它就能按预期工作了。当然,ViewState也不应该被禁用。


0

超级简单的答案是为该控件设置ViewState

只需在复选框标记中添加EnableViewState="true"AutoPostBack="true"属性即可。


0

CheckBox的“Checked”属性的默认值为false(表示未选中)。因此,当您勾选/取消复选框时,它会与Checked属性进行比较。

  • 如果与Checked属性不匹配,则ASP会触发OnCheckedChanged事件。
  • 如果与Checked属性匹配,则不会触发OnCheckedChanged事件。

因此,为了使ASP在取消选中时触发OnCheckedChanged事件,它必须知道原始值,以便将其与用户提供的值进行比较并触发事件。

通过在asp:CheckBox中添加data-originalValue='<%# Eval("ValueFromCodeBehind") %>'属性,ASP现在可以知道其先前的值,从而能够触发OnCheckChanged事件。因此,即使我们取消选中,当我们更改它时,ASP也会触发OnCheckChanged事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接