After a couple of days trying to get to grips with a misbehaving custom compositecontrol I finally located the issue to a feature/bug in the framework implementation of DropDownList and ListControls in general. There is an issue logged on Microsoft Connect but it has been closed as “by-design”. I don’t think that this behavior really is by-design but there are two contradicting features interacting with each other leaving Microsoft with no other choice but to say “by-design”.
The problems occur if you want to handle the SelectedIndexChanged event and turn off viewstate for a DropDownList.
- When you turn off ViewState for a DropDownList it will not restore it’s state automatically in a PostBack. You have to populate the listitems and set the SelectedIndex yourself – which is by design.
- The SelectedIndexChanged event is fired during postback processing if the currently selected index for the DropDownList is different from the index in the posted data – also by design.
- The default value for SelectedIndex is -1, again by design and the expected behavior.
The problem occurs in the interaction between these features since if ViewState has been disabled the SelectedIndex will always be -1 during postback processing. At the same time the currently selected value in the DropDownList will always be posted to the server on a form submit (postback). This causes the unwanted behaviour – the SelectedIndexChanged event is triggered even when the user hasn’t changed their selection in the DropDownList…
Enabling ViewState will fix the issue – but if you can’t or don’t want to do that here are two alternative solutions, both of which require you to create a new Control that inherits from DropDownList.
- Use ControlState to store the SelectedIndex between postbacks so that the event is only triggered when the user has actually changed the value – this breaks the expected behaviour of disabling ViewState, since the DropDownList shouldn’t be repopulated with items unless ViewState is enabled.
- Override LoadPostData and prohibit loading the posted data if EnableViewState is set to false, this will also stop the control from firing the OnSelectedIndexChanged event.
Neither of these is great since they both change an expected behaviour from occurring as it is configured. The second alternative is probably more “correct” but when you have these issues the problem is usually that you want the event to be fired even if ViewState is disabled so the first option is probably more useful.