I had a similar problem. I think the issue is that dynamically created controls are not kept in view state and don't survive a postback. Here is a comment ripped from my code that describes the solution that I came up with (it may not be the only one, but it worked for me).
This page is used to define a grid dynamically. The user clicks checkboxes to indicate which fields to include on the grid. The logic of this page does two essential things:
(1) It maintains the GridDefinition object that is kept in ViewState. (2) It reconstructs the programatically added controls (essentially everything in the table object) from the GridDefinition in ViewState on each postback. The dynamically added controls are NOT recreated on the postback from ViewState. Indeed, I found that if you don't recreate the controls, their events won't fire. Apparently:
"The process that matches controls to posted values occurs
after page_load completes, so it has to occur just like this
if you are to use this way."
When I get a control event indicating some change to the data, I have to reflect that change in the GridDefinition object stored in ViewState. That way, on the NEXT postback, the control can be recreated properly (e.g. a text box indicating the header text for a grid column).