10

無効モードでチェックボックスをレンダリングするための CheckBoxFor(t => t.boolValue, new { disabled="disabled" }) メソッド。

このメソッドは隠しフィールドもレンダリングします。

私の質問は、この非表示フィールドの無効なチェック ボックスの値が誤っているのはなぜですか? 隠しフィールドの目的は、デフォルトのチェックボックスの動作に加えて、いくつかの追加の動作を持たせることだと思います

この非表示フィールドの値が無効モードでもチェックボックスの状態に基づくように、デフォルトの MVC 機能をオーバーライドする方法はありますか?

4

4 に答える 4

14

hidden フィールドは、チェックボックスの値をブール値のプロパティにバインドするために使用されます。チェックボックスがチェックされていない場合、サーバーには何も送信されないため、ASP.NET MVC はこの非表示フィールドを使用して false を送信し、対応するブール フィールドにバインドします。カスタム ヘルパーを作成する以外に、この動作を変更することはできません。

disabled="disabled"これは、チェックボックスでuseを使用する代わりに、言わreadonly="readonly"れています。このようにして、ユーザーがその値を変更できないという同じ望ましい動作を維持しますが、フォームが送信されたときにその値がサーバーに送信されることに加えて:

@Html.CheckBoxFor(x => x.Something, new { @readonly = "readonly" })

アップデート:

コメント セクションで指摘されているように、このreadonly属性は Google Chrome では機能しません。もう 1 つの可能性は、さらに別の非表示フィールドを使用して、チェックボックスを無効にすることです。

@Html.HiddenFor(x => x.Something)
@Html.CheckBoxFor(x => x.Something, new { disabled = "disabled" })

更新 2:

隠しフィールドを追加した完全なテストケースを次に示します。

モデル:

public class MyViewModel
{
    public bool Foo { get; set; }
}

コントローラ:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel { Foo = true });
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return Content(model.Foo.ToString());
    }
}

意見:

@model MyViewModel

@using (Html.BeginForm())
{
    @Html.HiddenFor(x => x.Foo)
    @Html.CheckBoxFor(x => x.Foo, new { disabled = "disabled" })
    <button type="submit">OK</button>
}

フォームが送信されるとき、Foo プロパティの値は ですtrue。すべての主要なブラウザー (Chrome、FF、IE) でテストしました。

于 2012-06-13T08:53:09.350 に答える
3

クエリ文字列に追加されたパラメーターがごちゃごちゃしているように見え、開発者が何か間違ったことをしたと人々に思わせてしまいます。そこで、非表示の入力をレンダリングするかどうかを決定できる独自の InputExtensions クラスを作成するという極端な方法に頼りました。

以下は、私が作成した InputExtensions クラスです (完全な互換性を維持するために、既存の MVC コードに基づいています)。

public static class InputExtensions
{
    //
    // Checkboxes
    //

    public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, bool>> expression, bool renderHiddenInput)
    {
        if (renderHiddenInput)
        {
            return System.Web.Mvc.Html.InputExtensions.CheckBoxFor(htmlHelper, expression);
        }
        return CheckBoxFor(htmlHelper, expression, false);
    }

    public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, bool>> expression, object htmlAttributes, bool renderHiddenInput)
    {
        if (renderHiddenInput)
        {
            return System.Web.Mvc.Html.InputExtensions.CheckBoxFor(htmlHelper, expression, htmlAttributes);
        }
        return CheckBoxFor(htmlHelper, expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), false);
    }

    public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, bool>> expression, IDictionary<string, object> htmlAttributes,
        bool renderHiddenInput)
    {
        if (renderHiddenInput)
        {
            return System.Web.Mvc.Html.InputExtensions.CheckBoxFor(htmlHelper, expression, htmlAttributes);
        }

        if (expression == null)
        {
            throw new ArgumentNullException("expression");
        }

        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        bool? isChecked = null;
        if (metadata.Model != null)
        {
            bool modelChecked;
            if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked))
            {
                isChecked = modelChecked;
            }
        }

        return CheckBoxHelper(htmlHelper, metadata, ExpressionHelper.GetExpressionText(expression), isChecked, htmlAttributes);
    }

    private static MvcHtmlString CheckBoxHelper(HtmlHelper htmlHelper, ModelMetadata metadata, string name, bool? isChecked, IDictionary<string, object> htmlAttributes)
    {
        RouteValueDictionary attributes = ToRouteValueDictionary(htmlAttributes);

        bool explicitValue = isChecked.HasValue;
        if (explicitValue)
        {
            attributes.Remove("checked"); // Explicit value must override dictionary
        }

        return InputHelper(htmlHelper,
                           InputType.CheckBox,
                           metadata,
                           name,
                           value: "true",
                           useViewData: !explicitValue,
                           isChecked: isChecked ?? false,
                           setId: true,
                           isExplicitValue: false,
                           format: null,
                           htmlAttributes: attributes);
    }

    //
    // Helper methods
    //

    private static MvcHtmlString InputHelper(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, IDictionary<string, object> htmlAttributes)
    {
        string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
        if (string.IsNullOrEmpty(fullName))
        {
            throw new ArgumentException("Value cannot be null or empty.", "name");
        }

        var tagBuilder = new TagBuilder("input");
        tagBuilder.MergeAttributes(htmlAttributes);
        tagBuilder.MergeAttribute("type", HtmlHelper.GetInputTypeString(inputType));
        tagBuilder.MergeAttribute("name", fullName, true);

        string valueParameter = htmlHelper.FormatValue(value, format);
        var usedModelState = false;

        bool? modelStateWasChecked = GetModelStateValue(htmlHelper.ViewData, fullName, typeof(bool)) as bool?;
        if (modelStateWasChecked.HasValue)
        {
            isChecked = modelStateWasChecked.Value;
            usedModelState = true;
        }
        if (!usedModelState)
        {
            string modelStateValue = GetModelStateValue(htmlHelper.ViewData, fullName, typeof(string)) as string;
            if (modelStateValue != null)
            {
                isChecked = string.Equals(modelStateValue, valueParameter, StringComparison.Ordinal);
                usedModelState = true;
            }
        }
        if (!usedModelState && useViewData)
        {
            isChecked = EvalBoolean(htmlHelper.ViewData, fullName);
        }
        if (isChecked)
        {
            tagBuilder.MergeAttribute("checked", "checked");
        }
        tagBuilder.MergeAttribute("value", valueParameter, isExplicitValue);

        if (setId)
        {
            tagBuilder.GenerateId(fullName);
        }

        // If there are any errors for a named field, we add the css attribute.
        ModelState modelState;
        if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
        {
            if (modelState.Errors.Count > 0)
            {
                tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
            }
        }

        tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));

        return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.SelfClosing));
    }

    private static RouteValueDictionary ToRouteValueDictionary(IDictionary<string, object> dictionary)
    {
        return dictionary == null ? new RouteValueDictionary() : new RouteValueDictionary(dictionary);
    }

    private static object GetModelStateValue(ViewDataDictionary viewData, string key, Type destinationType)
    {
        ModelState modelState;
        if (viewData.ModelState.TryGetValue(key, out modelState))
        {
            if (modelState.Value != null)
            {
                return modelState.Value.ConvertTo(destinationType, culture: null);
            }
        }
        return null;
    }

    private static bool EvalBoolean(ViewDataDictionary viewData, string key)
    {
        return Convert.ToBoolean(viewData.Eval(key), CultureInfo.InvariantCulture);
    }
}

次に、次のようにメソッドを呼び出すことができます。

@Html.CheckBoxFor(t => t.boolValue, new { disabled="disabled" }, false)
于 2015-07-07T09:20:11.213 に答える
2

これが私が発見した簡単なヒントです。オブジェクトのブール値のデフォルト値を設定した場合。値を true/false としてタグを書き出すことができます (この値は、オブジェクトのデフォルトのブール値の反対である必要があります)。

<input type="checkbox" name="IsAllDayEvent" value="true" id="IsAllDayEvent" />

チェックボックスがチェックされている場合にのみ値が送信されるため、機能します。

于 2012-11-19T00:39:21.900 に答える
0

ダリンの答えは完全に問題ありませんが、無効にしたチェックボックスのポストバックを期待どおりに確認する別の方法があります。

このソリューションは、モデルのプロパティに基づいてチェックボックスが条件付きで無効になっているシナリオ、またはユーザーの選択またはクライアント側で取得したデータに基づいてクライアント側で有効/無効になっているシナリオでも機能します。

ビューをシンプルに保つことができます:(ここで無効に設定することはオプションです)

@Html.CheckBoxFor(m => m.Something, new { id = "somethingCheckbox", disabled = "disabled" })

これにより、Darinが述べたように、falseに設定された追加の非表示の入力フィールドが生成されるため、チェックボックスがオフの場合でもチェックボックスの値がポストバックされます。Somethingしたがって、チェックボックスがオンになっているかどうか、無効になっているかどうかに関係なく、フィールドは常にポストバックすることがわかっています。チェックボックスが無効になっている場合、常にとしてポストバックされるという唯一の問題False

送信する前に、JavaScriptの後処理でこれを修正できます。私の場合、コードはこれらの行に沿って何かを示しています。

var dataToPost = $form.serializeArray();

if (dataToPost != null) {
    for (var i = 0; i < dataToPost.length; i++) {
        if (dataToPost[i].name === "Something") {
            dataToPost[i].value = $("#somethingCheckbox").attr("checked") === "checked";
            }
        }
    }  
$.post($form.attr("action"), dataToPost)

シナリオに合わせて変更する必要があるかもしれませんが、アイデアを得る必要があります。

于 2013-03-21T20:49:57.173 に答える