32

I have a CheckBox on an ASP.NET Content Form like so:

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

In my code behind I have the following method:

protected void chkTest_CheckedChanged(object sender, EventArgs e)
{
}

When I load the page in the browser and click the CheckBox it becomes checked, the page posts back, and I can see chkTest_CheckedChanged being called.

When I then click the CheckBox again it becomes unchecked, the page posts back, however chkTest_CheckedChanged is not called.

The process is repeatable, so once the CheckBox is unchecked, checking it will fire the event.

I have View State disabled in the Web.Config, enabling View State causes this issue to disappear. What can I do to have reliable event firing while the View State remains disabled?

Update: If I set Checked="true" on the server tag the situation becomes reversed with the event firing when un-checking the CheckBox, but not the other way around.

Update 2: I've overridden OnLoadComplete in my page and from within there I can confirm that Request.Form["__EVENTTARGET"] is set correctly to the ID of my CheckBox.

Matt
  • 995
  • 1
  • 8
  • 18

10 Answers10

32

To fire CheckedChanged event set the following properties for CheckBox, AutoPostBack property should be true and should have a default value either checked false or true.

AutoPostBack="true" Checked="false"
DreamTeK
  • 32,537
  • 27
  • 112
  • 171
Able Alias
  • 3,824
  • 11
  • 58
  • 87
19

Implementing a custom CheckBox that stores the Checked property in ControlState rather than ViewState will probably solve that problem, even if the check box has AutoPostBack=false

Unlike ViewState, ControlState cannot be disabled and can be used to store data that is essential to the control's behavior.

I don't have a visual studio environnement right now to test, but that should looks like this:

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);
            }
        }
    }
}

more info here.

Johnny5
  • 6,664
  • 3
  • 45
  • 78
  • Thanks this works like magic. I can't believe in all the time I've been working in .Net I've never run into this issue until now. This also works on Dynamically created Checkboxes, just register them as "MyCheckBox" instances instead of the standard ones and your good to go. – pharophy Dec 10 '12 at 17:07
  • Big up - thanks. Why checkboxes can't work out of the box I don't know. – Duncan Howe Aug 11 '13 at 23:51
9

It doesn't fire because with viewstate disabled the server code does not know that the checkbox was previously checked, therefore it doesn't know the state changed. As far as asp.net knows the checkbox control was unchecked before the postback and is still unchecked. This also explains the reverse behavior you see when setting Checked="true".

joshb
  • 5,182
  • 4
  • 41
  • 55
  • I'm coming back to this after a year, so I can't remember exactly what my thoughts were back then, but you're right, the page lifecycle does cause this effect. I think possibly I was expecting that because the __EVENTTARGET was set to my checkbox that ASP.NET might be clever enough to realise it had changed. – Matt Aug 06 '11 at 17:28
6

It's an old post but I had to share my simple solution in order to help others who searched for this problem.

The solution is simple: Turn on AutoPostBack.

        <asp:CheckBox id="checkbox1" runat="server"
                AutoPostBack="True" //<<<<------
                Text="checkbox"
                OnCheckedChanged="knowJobCBOX_CheckedChanged"/>
albeck
  • 510
  • 1
  • 7
  • 16
6

I'm not sure but I guess that my solution is working only for .NET Framework 4.0:

Use ViewStateMode = "Disabled" to disable view state insted of EnableViewState="false". This will caution the same behavior except that you can save a local view state.

So, on your checkbox, set the attribute ViewStateMode = "Enabled" and the problem is solved, without implementing a custom checkbox.

1

I wanted to tidy things up a bit so I've just spent a bit of time testing a solution for this.

joshb is correct with his explanation for why the CheckBox behaves the way it does.

As I don't know how I got round this last year or even if I did (I can't remember what I was working on at the time to check), I've put together a simple solution/workaround.

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;
    }
}

If you now register CheckBox2 in your page and use it in place of your standard CheckBoxes, you will get the CheckedChanged event fired as you expect with ViewState disabled and AutoPostBack enabled.

The way this works is allowing the normal CheckBox to do its thing with validation and change checking, but then performs an additional check to see if it was the target of the event that caused the postback. If it was the target, it returns true to tell the framework to raise the CheckedChanged event.

Edit: Please note that this only solves the problem for AutoPostBack on the CheckBox. If the PostBack is invoked from anything else (a button, for example), the CheckedChanged event still exhibits the observed problem.

Matt
  • 995
  • 1
  • 8
  • 18
  • Might be helpful for case when LoadPostData is not calling http://stackoverflow.com/questions/3211200/asp-net-custom-control-when-is-loadpostdata-called – sll Mar 31 '13 at 16:41
0

I had the same problem. I have spent a lot of time on it and finally have solved it.

In my case the Checkbox was disabled by default:

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

It turns ViewState isn't loaded for disabled or invisible controls. So remove Enabled="false" or Visible="false" and it will work as expeceted. And of course ViewState shouldn't be disabled.

algreat
  • 8,592
  • 5
  • 41
  • 54
0

Additionally: Check for any errors in the JavaScript console.

I experienced the same exact issue described by OP except that it only happened in Safari (checkbox worked fine in Chrome and Firefox). Upon inspecting the JavaScript console, I found an error that was being thrown by a malformed jQuery selector.

In my case, I had $('a[id*=lbView') which was missing a closing ]. This threw an error in Safari but, surprisingly, not in Chrome nor in Firefox.

Mr.Z
  • 542
  • 2
  • 5
  • 18
0

The super easy answer is to set the ViewState on for that one control.

Just add the EnableViewState="true" to the AutoPostBack="true" property in the checkbox tag.

Olivier De Meulder
  • 2,493
  • 3
  • 25
  • 30
0

The default value of "Checked" Property of CheckBox is false (which means Uncheck). So, when you Check/Uncheck the CheckBox it compares with Checked Property.

  • If it does not match with Checked Property, ASP fires OnCheckedChanged Event.
  • If it matches with the Checked Property it will not fire the OnCheckedChanged Event.

So, in order to make ASP to fire OnCheckedChanged event when unchecking, it has to know Original value, so that it compares with the value from user and fires the event.

By adding data-originalValue='<%# Eval("ValueFromCodeBehind") %>' property in asp:CheckBox will be able to fire the OnCheckChanged Event as ASP can now able to know its previous value. So that when we change it, ASP fires OnCheckChanged Event even if we do Uncheck.

Timothy G.
  • 6,335
  • 7
  • 30
  • 46