ASP custom controls don't fire correct events
<p>I'm building a library of custom controls. My controls are inherited from CompositeControl.
Depending on the user's answer I have to insert more custom control.  I have a PlaceHolder (_ph) passed in from the client code.  I insert my controls into that PlaceHolder.</p>

<p>My problem is the control I inserted in the event handler does not fire its event, but it fires the parent event.  For example, if I have an EddDropDown A, and the user picks an answer, I have to create EddDropDown B and C in edd_SelectedIndexChanged.  When I pick an answer for B, it fires SelectedIndexChanged for A instead of B.</p>

<p>I think it has something to do with entering the page cycle late.  I don't know how to fix it.  Please help.  Really appreciate any assistant.
Thanks in advance.</p>

<p>this is an example of my controls:</p>

<pre><code>using System;
</code></pre>

<p>using System.Collections.Generic;
using System.Collections;</p>

<p>using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using CommerceBank.DueDiligence.ServiceProxies.Internal.Edd;
using System.Collections.Specialized;
using System.Runtime.Serialization;</p>

<p>namespace CommerceBank.DueDiligence.ClientFacade.WebForms
{
    public class EddDropDownListArgs : EventArgs
    {
        private int _iQuestionID;
        string _sAnswer = string.Empty;
        private DueDiligenceProfile _customerProfile;</p>

<pre><code>    public EddDropDownListArgs(int iQuestionID, string sAnswer,DueDiligenceProfile customer)
    {
        _iQuestionID = iQuestionID;
        _sAnswer = sAnswer;
        _customerProfile = customer;
    }
    public int QuestionID
    {
        get
        {
            return _iQuestionID;
        }
        set
        {
            _iQuestionID = value;
        }
    }
    public string Answer
    {
        get
        {
            return _sAnswer;
        }
        set
        {
            _sAnswer = value;
        }
    }
    public DueDiligenceProfile customerProfile
    {
        get
        {
            return _customerProfile;
        }
        set
        {
            _customerProfile = value;
        }
    }

}
public delegate void EddDropDownSelectedIndexChangedHandler(object sender, EddDropDownListArgs ce);



[
AspNetHostingPermission(SecurityAction.Demand,
    Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand,
    Level = AspNetHostingPermissionLevel.Minimal),
DefaultProperty("ID"),
ToolboxData("&lt;{0}:EddDropDown runat=\"server\"&gt; &lt;/{0}:EddDropDown&gt;"),
Serializable
]
public class EddDropDown : CompositeControl, IChannelControl,ISerializable, IPostBackEventHandler, IPostBackDataHandler
{
    [Serializable]
    struct EddDropDownData
    {
        public int _iQuestionID;
        public String _sQuestion;
        //public AnswerOption[] _PossibleAnswers;
        public String _sAnswer;
        //public DueDiligenceProfile _customerProfile;
    }

    [
    Bindable(true),
    Category("Appearance"),
    DefaultValue(""),
    Description("This is EddCheckBox"),
    Localizable(true)
    ]
    private int _iQuestionID=-1;
    private String _sQuestion = string.Empty;
    private AnswerOption[] _PossibleAnswers;
    private String _sAnswer = string.Empty;
    private DueDiligenceProfile _customerProfile;
    private EddDropDownData _data = new EddDropDownData();
    Label _lQuestion = null;
    DropDownList _ddl = null;

    #region implement custom events
    public event EddDropDownSelectedIndexChangedHandler SelectedIndexChanged;
    protected virtual void OnSelectedIndexChanged(EddDropDownListArgs eddEvent)
    {
        if (SelectedIndexChanged != null)
        {
            System.Diagnostics.Trace.WriteLine("OnSelectedIndexChanged. QuestionID:"
                + eddEvent.QuestionID
                + " Answer: "
                + eddEvent.Answer);
            SelectedIndexChanged(this, eddEvent);
        }
    }
    #endregion

    #region IPostBackEventHandler_implementation
    // Define the method of IPostBackEventHandler that raises change events.
    void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
    {
        System.Diagnostics.Trace.WriteLine("in RaisePostBackEvent" + eventArgument);
        OnSelectedIndexChanged(new EddDropDownListArgs(EDDQuestionID(), EDDAnswerValue(), _customerProfile));
    }
    #endregion

    #region IPostBackDataHandler_implementation
    bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
    {
        //System.Diagnostics.Trace.WriteLine("in LoadPostData");

        //int i = int.Parse(postCollection["SelectedIndex"]);
        //string s = postCollection["SelectedValue"];

        //if (SelectedIndex &gt;= 0)
        //    Page.RegisterRequiresRaiseEvent(this);
        //return false;
        return true;
    }
    void IPostBackDataHandler.RaisePostDataChangedEvent()
    {
        System.Diagnostics.Trace.WriteLine("in RaisePostDataChangedEvent");
    }
    #endregion

    #region ISerializable_implementation
    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("ControlType", GetType().Name);
        info.AddValue("ControlID", ID);
        info.AddValue("QuestionID", _iQuestionID);
        info.AddValue("Question", Question);
        info.AddValue("Answer", EDDAnswerValue());
        info.AddValue("PossibleAnswerCount", _PossibleAnswers.Length);
        for (int i=0; i &lt; _PossibleAnswers.Length; i++)
        {
            info.AddValue("a" + i.ToString(), _PossibleAnswers[i]);
        }
    }
    #endregion


    #region IChannel_implementation
    public int EDDQuestionID()
    {
        return QuestionID;
    }
    public string EDDAnswerValue()
    {
        EnsureChildControls();
        for (int i = 0; i &lt; Controls.Count; i++)
        {
            if (Controls[i].ID == "ans" + QuestionID)
            {
                _sAnswer = ((DropDownList)Controls[i]).SelectedValue;
                _data._sAnswer = ((DropDownList)Controls[i]).SelectedValue;
                ViewState["SelectedIndex"] = ((DropDownList)Controls[i]).SelectedIndex;

                return ((DropDownList)Controls[i]).SelectedValue;
            }
        }
        return null;
    }
    #endregion

    #region Overriden properties
    public override ControlCollection Controls
    {
        get
        {
            EnsureChildControls();
            return base.Controls;
        }
    }
    #endregion

    #region Properties
    public int QuestionID
    {
        get
        {
            _iQuestionID = (int)ViewState["QuestionID"];
            return _iQuestionID;
        }
        set
        {
            ViewState["QuestionID"] = value;
            _iQuestionID = value;
        }
    }
    public string Question
    {
        get
        {
            _sQuestion = (string)ViewState["Question"];
            return _sQuestion;
        }
        set
        {
            ViewState["Question"] = value;
            _sQuestion = value;
        }
    }
    public string Answer
    {
        get
        {
            return _sAnswer;
        }
        set
        {
            _sAnswer = value;
        }
    }
    public int SelectedIndex
    {
        get {
            EnsureChildControls();
            if (ViewState["SelectedIndex"] != null)
                _ddl.SelectedIndex = (int)ViewState["SelectedIndex"];
            else
                _ddl.SelectedIndex = 0;
            return _ddl.SelectedIndex;
        }
        set {
            EnsureChildControls();
            ViewState["SelectedIndex"] = value;
            _ddl.SelectedIndex = value;
        }
    }
    public string SelectedValue
    {
        get
        {
            EnsureChildControls();
            _ddl.SelectedValue =(string)ViewState["SelectedValue"];
            return _ddl.SelectedValue;
        }
        set 
        {
            EnsureChildControls();
            ViewState["SelectedValue"] = value;
            _ddl.SelectedValue = value;
        }
    }
    #endregion


    public EddDropDown(int iQuestionID
        , string sQuestion
        , DueDiligenceProfile cust
        , AnswerOption[] sPossibleAnswers
        )
    {
        System.Diagnostics.Trace.WriteLine("Add EddDropDown.  QuestionID :" 
                                            + iQuestionID.ToString() 
                                            + sQuestion);
        QuestionID = iQuestionID;
        Question = sQuestion;

        _data._iQuestionID = iQuestionID;
        _data._sQuestion = sQuestion;

        _PossibleAnswers = sPossibleAnswers;
        _customerProfile = cust;
        ID = iQuestionID.ToString()+GetCustomerID();


    }

    public EddDropDown(SerializationInfo info, StreamingContext context)
    {
        string sControlType = info.GetString("ControlType");
        ID = info.GetString("ControlID");
        QuestionID = info.GetInt32("QuestionID");
        Question = info.GetString("Question");
        string sAnswer = info.GetString("Answer");

        int iAnswerCount = info.GetInt32("PossibleAnswerCount");
        List&lt;AnswerOption&gt; answerOptions = new List&lt;AnswerOption&gt;();
        for (int i = 0; i &lt; iAnswerCount; i++)
        {
            Type t = typeof(AnswerOption);
            AnswerOption ao = (AnswerOption)info.GetValue("a" + i.ToString(), t);
            answerOptions.Add(ao);
        }

        _PossibleAnswers = answerOptions.ToArray();
    }
    protected override object SaveViewState()
    {
        ViewState["SelectedIndex"] = _ddl.SelectedIndex;

        return base.SaveViewState();
    }

    protected override void LoadViewState(object savedState)
    {
        //if (ViewState["SelectedIndex"] != null)
        //    _ddl.SelectedIndex = (int)ViewState["SelectedIndex"];
        //else
        //    _ddl.SelectedIndex = 0;
        if (savedState != null)
        {
            Pair mystate = (Pair)savedState;
            ArrayList al =(ArrayList)mystate.First;
            for (int i = 0; i &lt; al.Count;i++ )
            {
                if (al[i].GetType().Name == "IndexedString")
                {
                    if (((IndexedString)al[i]).Value == "SelectedIndex")
                    {
                        ViewState["SelectedIndex"] = al[i + 1].ToString();
                        System.Diagnostics.Trace.WriteLine(al[i + 1].ToString());
                    }
                }
            }



        }
        base.LoadViewState(savedState);
    }
    //need this to get the post back
    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        writer.AddAttribute(HtmlTextWriterAttribute.Name, this.ID);
        writer.AddAttribute(HtmlTextWriterAttribute.Onchange,
            Page.ClientScript.GetPostBackEventReference(this, ID));
        //writer.AddAttribute(HtmlTextWriterAttribute.Onchange,
        //    Page.ClientScript.GetPostBackEventReference(_ddl, _ddl.ID));
        base.AddAttributesToRender(writer);
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        Page.RegisterRequiresPostBack(this);//must register postback in OnPreRender
    }
    protected override void Render(HtmlTextWriter writer)
    {
        //Ensures that this control is nested in a server form
        if (Page != null)
        {
            Page.VerifyRenderingInServerForm(this);
        }
        base.Render(writer);
    }
    protected override void RenderContents(HtmlTextWriter writer)
    {
        RenderChildren(writer);
    }

    protected override void CreateChildControls()
    {
        Controls.Clear();

        _lQuestion = new Label();
        _lQuestion.ID = "quest" + QuestionID;
        _lQuestion.Text = Question;
        _ddl = new DropDownList();
        _ddl.ID = "ans" + QuestionID;

        //add "select one"
        ListItem liSelectOne = new ListItem("Please select one");
        _ddl.Items.Add(liSelectOne);
        for (int i = 0; i &lt; _PossibleAnswers.Count(); i++)
        {
            AnswerOption a = _PossibleAnswers[i];

            ListItem li = new ListItem(a.Value.ToString());
            _ddl.Items.Add(li);
            //if (a.ChildQuestions == null)//default it to the answer that don't have some children
            //    ddl.Items[i].Selected = true;
        }
        if (_sAnswer != string.Empty)
            _ddl.SelectedValue = _sAnswer;


        _ddl.AutoPostBack = true;//must have
        _ddl.SelectedIndexChanged += new EventHandler(ddl_SelectedIndexChanged);
        if (ViewState["SelectedIndex"] != null)
            _ddl.SelectedIndex = (int)ViewState["SelectedIndex"];
        //else
        //    _ddl.SelectedIndex = 0;

        Page.RegisterRequiresPostBack(_ddl);
        Page.RegisterRequiresControlState(_ddl);

        Controls.Add(new LiteralControl("&lt;br&gt;"));
        Controls.Add(_lQuestion);
        Controls.Add(new LiteralControl("&lt;br&gt;"));
        Controls.Add(_ddl);

        ChildControlsCreated = true;
        //ClearChildViewState();
    }
    private string GetCustomerID()
    {
        if (_customerProfile.Customer.PermanentId &gt;0)
            return _customerProfile.Customer.PermanentId.ToString();
        else if (_customerProfile.Customer.RcifId != null &amp;&amp; _customerProfile.Customer.RcifId != "")
            return _customerProfile.Customer.RcifId;
        else
            return _customerProfile.Customer.TaxId.ToString();
    }
    //to do: delete
    //void edd_SelectedIndexChanged(object sender, EddDropDownListArgs ea)
    //{
    //    System.Diagnostics.Trace.WriteLine("get here");
    //}
    void ddl_SelectedIndexChanged(object sender, EventArgs e)
    {
        Control c = (Control)sender;
        System.Diagnostics.Trace.WriteLine("ddl_SelectedIndexChanged " 
            + c.GetType().Name);
        OnSelectedIndexChanged(new EddDropDownListArgs(EDDQuestionID(), EDDAnswerValue(),_customerProfile));
    }
    protected override void RenderChildren(HtmlTextWriter output)
    {
        if (HasControls())
        {
            for (int i = 0; i &lt; Controls.Count; i++)
            {
                Controls[i].RenderControl(output);
            }
        }

    }



}
</code></pre>

<p>}</p>

<p>This is the code that create the controls:</p>

<pre><code>        public EddDropDown GetDropDown(DueDiligenceProfile cust, Question quest)
    {

        Control c = null;
        if (HasControl(quest.Id.ToString(), "EddDropDown", ref c))
            return (EddDropDown)c;
        string sQuestion = null;

        AnswerOption[] sPossAnswers;
        sPossAnswers = FindPossibleAnswers(cust.Questions, quest.Id, ref sQuestion);
        if (sPossAnswers == null)
            throw (new Exception("failed to get possible answers"));
        EddDropDown edd = new EddDropDown(quest.Id,
                            sQuestion,
                            cust,
                            sPossAnswers
                            );
        edd.ID = quest.Id.ToString();
        edd.SelectedIndexChanged += new EddDropDownSelectedIndexChangedHandler(edd_SelectedIndexChanged);
        _data._EDDControls.Add(edd);
        int iParentQuestionID = FindParentQuestionID(cust.Questions, quest.Id, ref sQuestion);
        int iControlIdx = GetIndexOf(iParentQuestionID, _ph.Controls);
        if (iControlIdx &gt;-1)
            _ph.Controls.AddAt(iControlIdx + 1, edd);
        else
            _ph.Controls.Add(edd);
        //build children questions if they have result
        if (quest.Results.Length &gt;0)
        {

            foreach (Result r in quest.Results)
            {
                edd.SelectedValue = r.Value;
                foreach (AnswerOption ao in quest.AnswerOptions)
                {
                    if (r.Value == ao.Value)
                    {
                        if (ao.ChildQuestions == null)
                            continue;
                        foreach (Question q in ao.ChildQuestions)
                        {
                            EddDropDown e = GetDropDown(cust, q);
                            e.BackColor = System.Drawing.Color.CadetBlue;
                        }
                    }
                }
            }
        }
        return edd;

    }
    void edd_SelectedIndexChanged(object sender, EddDropDownListArgs ea)
    {
        System.Diagnostics.Trace.WriteLine("EddQuestionare--edd_SelectedIndexChanged. QuestionID:"
                    + ea.QuestionID
                    + " Answer: "
                    + ea.Answer);

        //Control parentControl = null;
        //if (sender.GetType().Name == "EddDropDown")
        //{
        //    parentControl = (Control)sender;

        //}
        //Control c = (Control)sender;

        //while (c.GetType().Name != "PlaceHolder")
        //    c = c.Parent;

        string sQuestion = null;

        AnswerOption[] ansOptions = FindPossibleAnswers(ea.customerProfile.Questions
                                , ea.QuestionID
                                , ref sQuestion);

        foreach (AnswerOption ao in ansOptions)
        {
            if (ao.Value == ea.Answer)//found answer
            {
                if (ao.ChildQuestions == null)
                    break;

                //create sub questions
                for (int i = 0; i &lt; ao.ChildQuestions.Length; i++)//and there are subquestions
                {
                    _ph.Controls.Add(new LiteralControl("&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"));
                    if (ao.ChildQuestions[i].AnswerOptions.Length &gt; 2)
                    {
                        EddDropDown subQues = GetDropDown(ea.customerProfile
                                            , ao.ChildQuestions[i]);
                        subQues.BackColor = System.Drawing.Color.Aqua;
                    }
                    else if (ao.ChildQuestions[i].AnswerOptions.Length == 2)
                    {
                        EddRadioButtonList erb = GetRadioButtonList(ea.customerProfile
                                            , ao.ChildQuestions[i].Id);
                        erb.BackColor = System.Drawing.Color.BlueViolet;
                    }
                    else
                    { 
                        EddTextArea eta = GetTextArea(ea.customerProfile
                                            , ao.ChildQuestions[i].Id);
                        eta.BackColor = System.Drawing.Color.Bisque;
                    }
                }
                break;
            }
        }
        //DisplayControls();
        //Serialize();
    }
</code></pre>

<p>There are a few things that I haven't cleaned out, but you get the idea. </p>
