自定义BoundField不会在添加了LiteralControl的PostBack之间保留数据

时间:2013-07-11 01:13:44

标签: c# asp.net detailsview databound

我已创建了一个自定义BoundField,可与编辑插入模式中的DetailsView一起使用,以利用Twitter Bootstrap。

该控件工作正常,除非我在 InitializeDataCell(...)期间添加额外的LiteralControl以在TextBox周围添加一些HTML。与此相关的代码即将结束。

下面生成的HTML似乎与TemplateField生成的HTML相同。但是,当我触发更新时,只要它在此处添加额外的 div / span TextBox中的值为空在 PostBack

<div class="input-prepend">
    <span class="add-on">$</span>
    <input name="ctl00$ctl00$MainContent$MainContent$pi$dvPackage$tbPrice" type="text" value="0" size="5" id="MainContent_MainContent_pi_dvPackage_tbPrice" title="Price">
</div>

以下是我在前面的ASP.NET代码中正在做的事情以及生成HTML的一些示例。

不起作用 - 自定义字段 通过 Update 命令提交后,文本框内的值将被取消设置,仅当我添加 input-append add-on 部分时。

DetailsView中的字段

<my:ValidationField DataField="Price" HeaderText="Price" TextPrepend="$" />

HTML生成

<td>
    <div class="input-prepend">
        <span class="add-on">$</span>
        <input name="ctl00$ctl00$MainContent$MainContent$pi$dvPackage$tbPrice" type="text" value="0" size="5" id="MainContent_MainContent_pi_dvPackage_tbPrice" title="Price">
    </div>
</td>

是否有效 - 正常的TemplateField 工作正常

DetailsView中的字段

<asp:TemplateField>
    <EditItemTemplate>
        <div class="input-prepend">
            <span class="add-on">$</span>
            <asp:TextBox ID="tbCost" runat="server" Text='<%# Bind("Cost") %>'></asp:TextBox>
        </div>
    </EditItemTemplate>
</asp:TemplateField>

生成的HTML - 与上面的内容相同

<td>
    <div class="input-prepend">
        <span class="add-on">$</span>
        <input name="ctl00$ctl00$MainContent$MainContent$pi$dvPackage$tbPrice" type="text" value="0" size="5" id="MainContent_MainContent_pi_dvPackage_tbPrice" title="Price">
    </div>
</td>

可行 - 使用自定义字段生成HTML 当我不添加 TextPrepend 字段时,通过 Update 命令正确提交文本框内的值。

DetailsView中的字段

<my:ValidationField DataField="Price" HeaderText="Price" />

生成的HTML没有额外的span / div

<td>
    <input name="ctl00$ctl00$MainContent$MainContent$pi$dvPackage$tbPrice" type="text" value="0" size="5" id="MainContent_MainContent_pi_dvPackage_tbPrice" title="Price">
</td>
与此代码创建相关的

InitializeDataCell 部分

我认为这是由于 InitializeDataCell(...)实现的原因造成的。

protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
{
    base.InitializeDataCell(cell, rowState);

    // Find the text box to validate
    TextBox text = FindTextBox(cell);

    if (text != null)
    {
        text.ID = "tb" + DataField;
        text.MaxLength = MaxLength;
        text.TextMode = TextMode;
        text.Text = DataField;

        string cellCss = string.Empty;
        bool prepend = !string.IsNullOrEmpty(this.TextPrepend);
        bool append = !string.IsNullOrEmpty(this.TextAppend);
        bool addon = prepend || append;

        if (prepend == true)
            cellCss = this.ConcatenateCss(cellCss, "input-prepend");

        if (append == true)
            cellCss = this.ConcatenateCss(cellCss, "input-append");

        if (addon == true)
        {
            int textIndex = cell.Controls.IndexOf(text);

            Literal container = new Literal();
            container.Text = "<div class=\"" + cellCss + "\">";
            cell.Controls.AddAt(textIndex, container);
        }

        if (prepend == true)
        {
            int textIndex = cell.Controls.IndexOf(text);

            Literal units = new Literal();
            units.Text = "<span class=\"add-on\">" + this.Prepend() + "</span>";
            cell.Controls.AddAt(textIndex, units);
        }

        if (append == true)
        {
            Literal units = new Literal();
            units.Text = "<span class=\"add-on\">" + this.Append() + "</span>";
            cell.Controls.Add(units);
        }

        if (addon == true)
        {
            Literal container = new Literal();
            container.Text = "</div>";
            cell.Controls.Add(container);
        }
    }
}

整个代码,以防任何人尝试使用Twitter Bootstrap,或者我的代码在其他地方出错。

public class ValidationField : BoundField
{
    #region Properties
    public virtual string EditTextCssClass
    {
        get
        {
            return (string)(ViewState["EditTextCssClass"] ?? string.Empty);
        }

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

    public virtual ValidatorDisplay ErrorDisplay
    {
        get
        {
            return (ValidatorDisplay)(ViewState["ErrorDisplay"] ?? ValidatorDisplay.Dynamic);
        }

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

    public virtual string ErrorMessage
    {
        get
        {
            return (string)(ViewState["ErrorMessage"] ?? "Invalid value entered");
        }

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

    public virtual string HelpText
    {
        get
        {
            return (string)(ViewState["HelpText"] ?? string.Empty);
        }

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

    public virtual TwitterBootstrap.WebControls.TextBox.HelpTextDisplayMode HelpDisplay
    {
        get
        {
            return (TwitterBootstrap.WebControls.TextBox.HelpTextDisplayMode)(ViewState["HelpDisplay"] ?? TwitterBootstrap.WebControls.TextBox.HelpTextDisplayMode.Block);
        }

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

    public virtual int MaxLength
    {
        get
        {
            return (int)(ViewState["MaxLength"] ?? 0);
        }

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

    public virtual string PlaceHolder
    {
        get
        {
            return (string)(ViewState["PlaceHolder"] ?? string.Empty);
        }

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

    public virtual bool Required
    {
        get
        {
            return (bool)(ViewState["Required"] ?? false);
        }

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

    public virtual TextBoxMode TextMode
    {
        get
        {
            return (TextBoxMode)(ViewState["TextMode"] ?? TextBoxMode.SingleLine);
        }

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

    public virtual string ValidationExpression
    {
        get
        {
            return (string)(ViewState["ValidationExpression"] ?? string.Empty);
        }

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

    public virtual string ValidationGroup
    {
        get
        {
            return (string)(ViewState["ValidationGroup"] ?? string.Empty);
        }

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

    public virtual string TextAppend
    {
        get
        {
            object value = ViewState["TextAppend"];
            if (value != null)
                return value.ToString();

            return string.Empty;
        }

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

    public virtual string TextPrepend
    {
        get
        {
            object value = ViewState["TextPrepend"];
            if (value != null)
                return value.ToString();

            return string.Empty;
        }

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

    #endregion

    public ValidationField()
    {

    }

    protected override DataControlField CreateField()
    {
        return new ValidationField();
    }

    protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
    {
        base.InitializeDataCell(cell, rowState);

        // Find the text box to validate
        TextBox text = FindTextBox(cell);

        if (text != null)
        {
            text.ID = "tb" + DataField;
            text.MaxLength = MaxLength;
            text.TextMode = TextMode;
            text.CssClass = EditTextCssClass;
            text.Text = DataField;

            if (PlaceHolder != string.Empty)
                text.Attributes.Add("placeholder", PlaceHolder);

            string cellCss = string.Empty;
            bool prepend = !string.IsNullOrEmpty(this.TextPrepend);
            bool append = !string.IsNullOrEmpty(this.TextAppend);
            bool addon = prepend || append;

            if (prepend == true)
                cellCss = this.ConcatenateCss(cellCss, "input-prepend");

            if (append == true)
                cellCss = this.ConcatenateCss(cellCss, "input-append");

            if (addon == true)
            {
                int textIndex = cell.Controls.IndexOf(text);

                Literal container = new Literal();
                container.Text = "<div class=\"" + cellCss + "\">";
                cell.Controls.AddAt(textIndex, container);
            }

            if (prepend == true)
            {
                int textIndex = cell.Controls.IndexOf(text);

                Literal units = new Literal();
                units.Text = "<span class=\"add-on\">" + this.Prepend() + "</span>";
                cell.Controls.AddAt(textIndex, units);
            }

            if (append == true)
            {
                Literal units = new Literal();
                units.Text = "<span class=\"add-on\">" + this.Append() + "</span>";
                cell.Controls.Add(units);
            }

            if (addon == true)
            {
                Literal container = new Literal();
                container.Text = "</div>";
                cell.Controls.Add(container);
            }

            if (Required == true)
            {
                Literal required = new Literal();
                required.Text = "<span class=\"required\">*</span>";
                cell.Controls.Add(required);
            }

            if (HelpText != string.Empty)
            {
                Label lblHelpText = new Label();
                if (HelpDisplay == TwitterBootstrap.WebControls.TextBox.HelpTextDisplayMode.Block)
                    lblHelpText.CssClass = "help-block";
                else
                    lblHelpText.CssClass = "help-inline";
                lblHelpText.Text = HelpText;
                cell.Controls.Add(lblHelpText);
            }

            if (Required == true)
            {
                // Add a RequiredFieldValidator
                RequiredFieldValidator required = new RequiredFieldValidator();
                required.ErrorMessage = ErrorMessage;
                required.Display = ErrorDisplay;
                required.ControlToValidate = text.ID;
                required.Text = "";

                if (ValidationGroup != string.Empty)
                    required.ValidationGroup = ValidationGroup;

                cell.Controls.Add(required);
            }

            if (ValidationExpression != string.Empty)
            {
                // Add a RequiredFieldValidator
                RegularExpressionValidator regex = new RegularExpressionValidator();
                regex.ErrorMessage = ErrorMessage;
                regex.Display = ErrorDisplay;
                regex.ControlToValidate = text.ID;
                regex.ValidationExpression = ValidationExpression;

                if (ValidationGroup != string.Empty)
                    regex.ValidationGroup = ValidationGroup;

                cell.Controls.Add(regex);
            }
        }
    }

    #region Methods
    private string ConcatenateCss(params string[] classes)
    {
        string result = string.Empty;
        foreach (string s in classes)
            result += s + " ";

        return result.TrimEnd().TrimStart();
    }

    private static TextBox FindTextBox(Control parent)
    {
        TextBox result = null;
        foreach (Control control in parent.Controls)
        {
            if (control is TextBox)
            {
                result = control as TextBox;
                break;
            }
        }
        return result;
    }

    protected virtual string Prepend()
    {
        return this.TextPrepend;
    }

    protected virtual string Append()
    {
        return this.TextAppend;
    }

    #endregion
}

1 个答案:

答案 0 :(得分:0)

我设法弄清楚为什么会这样。由于Control集合在字段中已更改,因此您还必须覆盖_ExtractValuesFromCell(...)to get the TextBox`值。

我使用了ASP.NET Boundfield overridden to support Dropdownlist is missing one final feature稍微改变的实现,并没有针对我的用例进行优化。但是,它现在工作正常。

public override void ExtractValuesFromCell(System.Collections.Specialized.IOrderedDictionary dictionary, DataControlFieldCell cell, DataControlRowState rowState, bool includeReadOnly)
{
    Control control = null;
    string dataField = DataField;
    object text = null;
    string nullDisplayText = NullDisplayText;
    if (((rowState & DataControlRowState.Insert) == DataControlRowState.Normal) || InsertVisible)
    {
        if (cell.Controls.Count > 0)
        {
            foreach (Control c in cell.Controls)
            {
                control = cell.Controls[0];

                if (c is TextBox)
                {
                    text = ((TextBox)c).Text;
                } 
            }
        }
        else if (includeReadOnly)
        {
            string s = cell.Text;
            if (s == "&nbsp;")
            {
                text = string.Empty;
            }
            else if (SupportsHtmlEncode && HtmlEncode)
            {
                text = HttpUtility.HtmlDecode(s);
            }
            else
            {
                text = s;
            }
        }
        if (text != null)
        {
            if (((text is string) && (((string)text).Length == 0)) && ConvertEmptyStringToNull)
            {
                text = null;
            }
            if (((text is string) && (((string)text) == nullDisplayText)) && (nullDisplayText.Length > 0))
            {
                text = null;
            }
            if (dictionary.Contains(dataField))
            {
                dictionary[dataField] = text;
            }
            else
            {
                dictionary.Add(dataField, text);
            }
        }
    }
}