【问题标题】:MVC Custom TextBoxFor with CheckBoxFor extension带有 CheckBoxFor 扩展的 MVC 自定义 TextBoxFor
【发布时间】:2015-10-23 01:01:12
【问题描述】:

我正在尝试将此剃须刀代码转换为 C# 代码。但是,复选框回发有问题。

<div class="input-group">
   @Html.TextBoxFor(model => model.Property1, new { @class = "form-control js-template-text", data_val = "false" }
   <span class="input-group-addon">
       @Html.CheckBoxFor(model => model.Property2, new { data_val = "false" })
       @Html.HiddenFor(model => model.Property2)
       <span class="glyphicon glyphicon-phone glyphicon-green"></span>
   </span>
</div>

这部分标记工作得很好。 但是从这个 c# 代码生成的标记没有。两种方法生成的标记是相同的。 我的问题是:代码中需要进行哪些修改(如果有的话),以便浏览器发送正确的复选框值。

private static MvcHtmlString CreateTextBoxCheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, string>> textBoxExpression, Expression<Func<TModel, bool>> checkBoxExpression, IGlyphIcon checkBoxGlyphIcon = null, IDictionary<string, object> htmlAttributes = null, IDictionary<string, object> textBoxHtmlAttributes = null, IDictionary<string, object> checkBoxHtmlAttributes = null)
{
    var sb = new StringBuilder();

    #region OuterDiv

    var outerDivTag = new TagBuilder("div");
    outerDivTag.MergeAttributes(htmlAttributes);
    outerDivTag.AddCssClass("input-group");
    sb.AppendLine(outerDivTag.ToString(TagRenderMode.StartTag));

    #endregion OuterDiv

    #region TextBox

    var textBoxName = ExpressionHelper.GetExpressionText(textBoxExpression);
    var textBoxFullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(textBoxName);
    var textBoxId = TagBuilder.CreateSanitizedId(textBoxFullName);

    var textBoxMetaData = ModelMetadata.FromLambdaExpression(textBoxExpression, htmlHelper.ViewData);
    var textBoxValue = textBoxMetaData.Model.ToString();

    var textBoxTag = new TagBuilder("input");
    textBoxTag.Attributes.Add("type", "text");
    textBoxTag.Attributes.Add("class", "form-control");
    textBoxTag.Attributes.Add("name", textBoxFullName);
    textBoxTag.Attributes.Add("id", textBoxId);
    textBoxTag.Attributes.Add("value", textBoxValue);

    // get data annotation/client side scripts attributes
    var textkBoxValidationAttributes = htmlHelper.GetUnobtrusiveValidationAttributes(textBoxFullName, textBoxMetaData);
    foreach (var key in textkBoxValidationAttributes.Keys)
    {
        textBoxTag.Attributes.Add(key, textkBoxValidationAttributes[key].ToString());
    }

    textBoxTag.MergeAttributes(textBoxHtmlAttributes, true);
    sb.AppendLine(textBoxTag.ToString(TagRenderMode.SelfClosing));

    #endregion TextBox

    #region CheckBox

    var checkBoxSpan = new TagBuilder("span");
    checkBoxSpan.Attributes.Add("class", "input-group-addon");

    var checkBoxName = ExpressionHelper.GetExpressionText(checkBoxExpression);
    var checkBoxFullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(checkBoxName);
    var checkBoxId = TagBuilder.CreateSanitizedId(checkBoxFullName);

    var checkBoxMetaData = ModelMetadata.FromLambdaExpression(checkBoxExpression, htmlHelper.ViewData);
    var checkBoxValue = checkBoxMetaData.Model.ToString().ToLower();

    var checkBoxTag = new TagBuilder("input");
    checkBoxTag.Attributes.Add("type", "checkbox");
    checkBoxTag.Attributes.Add("name", checkBoxFullName);
    checkBoxTag.Attributes.Add("id", checkBoxId);
    checkBoxTag.Attributes.Add("value", checkBoxValue);
    if (checkBoxValue.Equals("true", StringComparison.InvariantCultureIgnoreCase))
    {
        checkBoxTag.Attributes.Add("checked", "checked");
    }

    // get data annotation/client side scripts attributes
    var validationAttributes = htmlHelper.GetUnobtrusiveValidationAttributes(checkBoxFullName, checkBoxMetaData);
    foreach (var key in validationAttributes.Keys)
    {
        checkBoxTag.Attributes.Add(key, validationAttributes[key].ToString());
    }

    checkBoxTag.MergeAttributes(checkBoxHtmlAttributes, true);

    // to keep track of checkbox postbacks, create hidden input for checkbox
    var checkBoxHiddenTag = new TagBuilder("input");
    checkBoxHiddenTag.Attributes.Add("name", checkBoxFullName);
    checkBoxHiddenTag.Attributes.Add("id", checkBoxId);
    checkBoxHiddenTag.Attributes.Add("type", "hidden");
    checkBoxHiddenTag.Attributes.Add("value", checkBoxValue.Equals("true", StringComparison.InvariantCultureIgnoreCase) ? "True" : "False");

    sb.AppendLine(checkBoxSpan.ToString(TagRenderMode.StartTag));
    sb.AppendLine(checkBoxTag.ToString(TagRenderMode.SelfClosing));
    sb.AppendLine(checkBoxHiddenTag.ToString(TagRenderMode.SelfClosing));

    #endregion CheckBox

    #region GlyphIcon

    if (checkBoxGlyphIcon != null)
    {
        var checkBoxGlyphIconSpan = new TagBuilder("span");
        checkBoxGlyphIconSpan.Attributes.Add("class", checkBoxGlyphIcon.CssClass);
        sb.AppendLine(checkBoxGlyphIconSpan.ToString(TagRenderMode.StartTag));
        sb.AppendLine(checkBoxGlyphIconSpan.ToString(TagRenderMode.EndTag));
    }

    #endregion GlyphIcon

    sb.AppendLine(checkBoxSpan.ToString(TagRenderMode.EndTag));
    sb.AppendLine(outerDivTag.ToString(TagRenderMode.EndTag));
    var result = MvcHtmlString.Create(sb.ToString());
    return result;
}

【问题讨论】:

  • 你的问题是什么。你有什么问题?
  • 你有什么理由不只使用内置扩展而不是尝试重新发明轮子 - 例如。 sb.append(htmlHelper.TextBoxFor(....));
  • @StephenMuecke,问题是浏览器不使用扩展方法回发复选框值(正确),但它使用剃刀标记。
  • @StephenMuecke 至于为什么不使用现有的框架扩展,首先尝试了,但它以某种方式生成了带有额外字符的标记,从而阻止了表单提交。花了一段时间才弄清楚。
  • 我知道,如果初始值为true,即使您取消选中复选框,它也会始终回复true :)。但是你需要在你的问题中解释问题(不要指望别人猜到问题)。

标签: c# asp.net-mvc


【解决方案1】:

首先,您的视图代码包含@Html.HiddenFor(model =&gt; model.Property2),这有点无意义,应该删除。 CheckBoxFor() 方法正确地为属性呈现隐藏输入,其值为False。幸运的是,DefaultModelBinder 忽略了此输入(否则您只会回发属性的原始值)。

您声称​​“从两种方法生成的标记是相同的” 是不正确的,您的代码正在生成一个复选框和一个隐藏输入,其中隐藏输入的值 id 的初始值由于您使用了该财产

checkBoxHiddenTag.Attributes.Add("value", checkBoxValue.Equals("true", StringComparison.InvariantCultureIgnoreCase) ? "True" : "False");

这意味着如果

  1. 初始值为false 并且复选框被选中你发布 返回 TrueFalse 导致 true(仅限模型活页夹 使用第一个值)
  2. 初始值为false,您发布的复选框未选中 返回False 导致false
  3. 初始值为true,复选框被选中你发布 返回 TrueFalse 导致 true
  4. 初始值为true,您发布的复选框未选中 返回True 导致true(这是您的问题所在)

您的代码还有许多其他问题,包括如果您因验证错误而返回视图,则您没有绑定到 ModelState

如果你想手动完成这一切,我建议你研究source code,但所有这些都可以通过使用内置方法来简化

StringBuilder html = new StringBuilder()
html.Append(htmlHelper.CheckBoxFor(checkBoxExpression, checkBoxHtmlAttributes).ToString());

if (checkBoxGlyphIcon != null)
{
    var checkBoxGlyphIconSpan = new TagBuilder("span");
    checkBoxGlyphIconSpan.Attributes.Add("class", checkBoxGlyphIcon.CssClass);
    html.Append(checkBoxGlyphIconSpan.ToString());
}

var checkBoxSpan = new TagBuilder("span");
checkBoxSpan.Attributes.Add("class", "input-group-addon");
checkBoxSpan.InnerHtml = html.ToString();

html = new StringBuilder();
html.Append(htmlHelper.TextBoxFor(textBoxExpression, textBoxHtmlAttributes).ToString());
html.Append(checkBoxSpan.ToString());

var outerDivTag = new TagBuilder("div");
outerDivTag.MergeAttributes(htmlAttributes);
outerDivTag.AddCssClass("input-group");
outerDivTag.InnerHtml = html.ToString();

MvcHtmlString.Create(outerDivTag.ToString());

【讨论】:

  • 谢谢,干净整洁。
猜你喜欢
  • 2016-03-28
  • 1970-01-01
  • 2022-11-10
  • 2014-08-02
  • 1970-01-01
  • 2014-01-23
  • 2018-07-16
  • 2013-11-17
  • 1970-01-01
相关资源
最近更新 更多