ExtractValuesFromCell has no controls in DataControlField
<p>I've created a custom <code>DataControlField</code> that is used in a <code>DetailsView</code> (Full control at end) which displays a <code>DropDownList</code> when in <em>Edit</em> mode and a <code>Label</code> with the selected text in <em>Read</em> mode.</p>

<pre><code>&lt;asp:DetailsView ID="dvPayPeroid1" runat="server"
    AutoGenerateRows="False"
    CssClass="DetailsView"
    DataSourceID="sqlMyScheduleData"
    DefaultMode="ReadOnly"
    GridLines="None"&gt;
    &lt;FieldHeaderStyle CssClass="DetailsViewHeader" /&gt;
    &lt;Fields&gt;
        &lt;asp:BoundField DataField="FirstDayOfWeek" HeaderText="Week Starting" HtmlEncode="false" DataFormatString="{0:MM/dd/yyyy}" ReadOnly="true" /&gt;
        &lt;my:ScheduleField DataField="1" HeaderText="Sunday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="2" HeaderText="Monday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="3" HeaderText="Tuesday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="4" HeaderText="Wednesday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="5" HeaderText="Thursday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="6" HeaderText="Friday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="7" HeaderText="Saturday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;asp:BoundField DataField="FirstDayOfSecondWeek" HeaderText="Week Starting" HtmlEncode="false" DataFormatString="{0:MM/dd/yyyy}" ReadOnly="true" /&gt;
        &lt;my:ScheduleField DataField="8" HeaderText="Sunday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="9" HeaderText="Monday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="10" HeaderText="Tuesday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="11" HeaderText="Wednesday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="12" HeaderText="Thursday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="13" HeaderText="Friday" DataSourceID="sqlReasonCodes" /&gt;
        &lt;my:ScheduleField DataField="14" HeaderText="Saturday" DataSourceID="sqlReasonCodes" /&gt;
    &lt;/Fields&gt;
&lt;/asp:DetailsView&gt;
</code></pre>

<p>What I am trying to do is get values back from the custom field when I use <code>DetailsView.UpdateItem(...)</code>. Calling this method goes through each field and executes <code>ExtractValuesFromCell(...)</code> for that field. However, the <code>DataControlFieldCell</code> reports having no <code>Control</code>s so it never adds the value of the field to the keys.</p>

<pre><code>public override void ExtractValuesFromCell(IOrderedDictionary dictionary, DataControlFieldCell cell, DataControlRowState rowState, bool includeReadOnly)
{
    base.ExtractValuesFromCell(dictionary, cell, rowState, includeReadOnly);

    // always 0 controls, never gets past this
    if (cell.Controls.Count &gt; 0)
    {
        DropDownList ddlReason = (DropDownList)cell.Controls[0];

        object selectedValue = null;
        if (ddlReason == null)
            throw new InvalidOperationException("ScheduleField could not extract control.");
        else
            selectedValue = ddlReason.SelectedValue;

        // Add the value of the ddl 
        if (dictionary.Contains(DataField))
            dictionary[DataField] = selectedValue;
        else
            dictionary.Add(DataField, selectedValue);
    }
}
</code></pre>

<p><strong>Does anyone know why this has no controls?</strong> Controls are added during the <code>InitializeCell</code> call. Here is the full control.</p>

<pre><code>public class ScheduleField : DataControlField
{
    #region Properties
    public string CssClass
    {
        get
        {
            object value = ViewState["CssClass"];

            if (value != null)
                return value.ToString();

            return "MetricStatus";
        }

        set
        {
            ViewState["CssClass"] = value;
            OnFieldChanged();
        }
    }

    public string DataSourceID
    {
        get
        {
            object value = ViewState["DataSourceID"];

            if (value != null)
                return Convert.ToString(value);

            return "";
        }

        set
        {
            ViewState["DataSourceID"] = value;
            OnFieldChanged();
        }
    }

    public string DataField
    {
        get
        {
            object value = ViewState["DataField"];

            if (value != null)
                return Convert.ToString(value);

            return "";
        }

        set
        {
            ViewState["DataField"] = value;
            OnFieldChanged();
        }
    }
    #endregion

    #region Constructors
    public ScheduleField()
    {

    }

    #endregion

    #region Abstract / Override Implementations
    protected override DataControlField CreateField()
    {
        return new ScheduleField();
    }

    public override void ExtractValuesFromCell(IOrderedDictionary dictionary, DataControlFieldCell cell, DataControlRowState rowState, bool includeReadOnly)
    {
        base.ExtractValuesFromCell(dictionary, cell, rowState, includeReadOnly);

        if (cell.Controls.Count &gt; 0)
        {
            DropDownList ddlReason = (DropDownList)cell.Controls[0];

            object selectedValue = null;
            if (ddlReason == null)
                throw new InvalidOperationException("ScheduleField could not extract control.");
            else
                selectedValue = ddlReason.SelectedValue;

            // Add the value of the ddl 
            if (dictionary.Contains(DataField))
                dictionary[DataField] = selectedValue;
            else
                dictionary.Add(DataField, selectedValue);
        }
    }

    public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
    {
        base.InitializeCell(cell, cellType, rowState, rowIndex);

        if (cellType == DataControlCellType.DataCell)
        {
            if ((rowState &amp; DataControlRowState.Edit) &gt; 0)
                cell.DataBinding += new EventHandler(cell_DataBinding_Edit);
            else if (rowState == DataControlRowState.Normal || rowState == DataControlRowState.Alternate)
                cell.DataBinding += new EventHandler(cell_DataBinding_Normal);
            else
                throw new Exception("Unhandled rowState: " + rowState.ToString());
        }
    }


    #endregion

    #region Events
    private void cell_DataBinding_Edit(object sender, EventArgs e)
    {
        DataControlFieldCell cell = (DataControlFieldCell)sender;
        object dataItem = DataBinder.GetDataItem(cell.NamingContainer);
        string sDataField = DataBinder.GetPropertyValue(dataItem, DataField).ToString();

        DropDownList ddlReason = new DropDownList();
        ddlReason.Items.Add(new ListItem("&lt;none&gt;", ""));
        ddlReason.AppendDataBoundItems = true;
        ddlReason.DataSourceID = this.DataSourceID;
        ddlReason.DataTextField = "Name";
        ddlReason.DataValueField = "Short";
        ddlReason.SelectedValue = sDataField;

        cell.Controls.Add(ddlReason);
    }

    private void cell_DataBinding_Normal(object sender, EventArgs e)
    {
        DataControlFieldCell cell = (DataControlFieldCell)sender;
        object dataItem = DataBinder.GetDataItem(cell.NamingContainer);
        string sDataField = DataBinder.GetPropertyValue(dataItem, DataField).ToString();

        ContentPlaceHolder cph = (ContentPlaceHolder)cell.Parent.Parent.Parent.Parent;
        SqlDataSource sds = (SqlDataSource)cph.FindControl("sqlReasonCodes");
        DataView dv = (DataView)sds.Select(DataSourceSelectArguments.Empty);
        DataTable dt = dv.ToTable();

        foreach (DataRow dr in dt.Rows)
        {
            if (dr["Short"].ToString() == sDataField)
                sDataField = dr["Name"].ToString();
        }

        Label lblReason = new Label();
        lblReason.Text = sDataField;

        cell.Controls.Add(lblReason);
    }

    #endregion

    #region Methods

    #endregion
}
</code></pre>
