2012-06-13 8 views
8

CheckBoxFor (t => t.boolValue, neu {disabled = "disabled") deaktiviert wurde , im deaktivierten Modus.Asp .net mvc 3 CheckBoxFür die Methode Ausgeblendetes Feld ist der Wert des ausgeblendeten Felds false, wenn das Kontrollkästchen mit der ausgewählten Methode true

Die Methode rendert auch ein verstecktes Feld.

Meine Frage ist, warum hat dieses versteckte Feld einen falschen Wert für deaktiviert Kontrollkästchen? Ich glaube, der Zweck des versteckten Feldes ist

Ist etwas mehr Verhalten über das Standard-Checkbox-Verhalten hat es eine Möglichkeit, Standard-MVC-Funktionalität außer Kraft zu setzen, so dass der Wert dieses versteckten Feldes auf dem Stand der zugrunde Kontrollkästchen auch im deaktivierten Modus?

+0

I habe eine Lösung zur Verfügung gestellt, die die Möglichkeit bietet, Checkboxen ohne ein verstecktes Feld zu verwenden, indem ein zusätzliches Argument übergeben wird. –

Antwort

14

Das ausgeblendete Feld wird verwendet, um den Wert des Kontrollkästchens an eine boolesche Eigenschaft zu binden. Die Sache ist, dass, wenn ein Kontrollkästchen nicht aktiviert ist, nichts an den Server gesendet wird, sodass ASP.NET MVC dieses versteckte Feld verwendet, um false zu senden und an das entsprechende boolesche Feld zu binden. Sie können dieses Verhalten nicht anders als das Schreiben eines benutzerdefinierten Helpers ändern.

Dies gesagt, statt disabled="disabled" verwenden Sie readonly="readonly" auf das Kontrollkästchen. Auf diese Weise kann die gleichen gewünschten Verhalten hält, dass der Benutzer seinen Wert nicht ändern kann, sondern zusätzlich zu, dass sein Wert wird an den Server gesendet werden, wenn das Formular abgeschickt wird:

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

UPDATE:

Wie in den Kommentaren erwähnt, funktioniert das Attribut readonly nicht mit Google Chrome. Eine weitere Möglichkeit ist ein weiterer verstecktes Feld zu verwenden, und deaktivieren Sie das Kontrollkästchen:

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

UPDATE 2:

Hier ist ein vollständiger Testfall mit dem zusätzlichen versteckten Feld.

Modell:

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

Controller:

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

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

Ausblick:

@model MyViewModel 

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

Wenn die Form den Wert der Eigenschaft Foo abgegeben wird, ist true. Ich habe mit allen gängigen Browsern (Chrome, FF, IE) getestet.

+0

Nun, die Sache ist readonly funktioniert nicht mit Kontrollkästchen. Atleast in Chrom. Ja, Sie haben recht, wenn Sie das Kontrollkästchen für das ausgeblendete Feld deaktivieren möchten. Mein Wunsch ist, dass das gleiche versteckte Feld verwendet werden kann, um den deaktivierten Teil zu behandeln, wenn man bedenkt, dass das Lesen nicht funktioniert. Mit welchem ​​Browser hast du readonly probiert? – Shameet

+0

@Shameet, oh ja, du hast absolut recht. Readonly funktioniert nicht mit Checkboxen. Ich habe meine Antwort mit einem anderen Vorschlag aktualisiert. –

+0

Darin, ein Extra mit dem gleichen Eigenschaftennamen versteckt funktioniert nicht. Der Modellbinder setzt die Eigenschaft immer noch auf false. Eine andere Eigenschaft (mit ihrer ausgeblendeten) zu haben, die deaktiviert werden kann, wird funktionieren, aber mit viel zu handhabendem Code. Ich denke, das Schreiben eigener Templated Views für Boolean wird eine elegante Lösung sein? – Shameet

2

Hier ist ein kurzer Tipp, den ich entdeckte: Wenn Sie einen Standardwert für den booleschen Wert für das Objekt festlegen. Es ist möglich, den Tag mit dem Wert true/false (soll dieser Wert auf dem Objekt das Gegenteil von dem Standard boolean Wert) zu schreiben

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

Der Wert nur, wenn das Kontrollkästchen gesendet wird, wird überprüft, so dass es funktioniert.

0

Obwohl Darins Antwort vollkommen in Ordnung ist, gibt es eine andere Möglichkeit, sicherzustellen, dass das deaktivierte Kontrollkästchen wie erwartet zurückgeschrieben wird.

Diese Lösung funktioniert auch in den Szenarien, in denen das Kontrollkästchen abhängig von einer Eigenschaft in einem Modell oder basierend auf der Benutzerauswahl oder clientseitig abgerufenen Daten clientseitig deaktiviert ist.

Sie können Ihre Ansicht einfach halten: (Einstellung hier deaktiviert ist optional)

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

Dies wird als Darin ein extra versteckte Eingabefeld auf false gesetzt erzeugen erwähnt, so dass das Kontrollkästchen Wert Post-back wird Auch wenn das Kontrollkästchen nicht aktiviert ist. Daher wissen wir, dass das Feld Something immer zurückschlägt, unabhängig davon, ob das Kontrollkästchen aktiviert ist oder nicht, ob es deaktiviert ist oder nicht. Das einzige Problem, wenn das Kontrollkästchen deaktiviert ist, wird immer als False zurückgesendet.

Wir können das mit einigen javaScript Post-Processing vor dem Senden beheben. In meinem Fall sieht der Code etwas in diese Richtung:

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) 

Möglicherweise müssen Sie es für Ihr Szenario ändern, aber Sie sollten die Idee.

3

Ich finde der hinzugefügte Parameter in der Abfrage-Zeichenfolge sieht ein Durcheinander und bringt die Leute dazu zu denken, dass wir als Entwickler etwas falsch gemacht haben. Also habe ich mich an die extreme Methode gewandt, meine eigene InputExtensions-Klasse zu erstellen, mit der ich entscheiden kann, ob die versteckte Eingabe gerendert werden soll oder nicht.

Das Folgende ist die InputExtensions Klasse I erstellt haben (basierend auf dem vorhandenen Code MVC volle Kompatibilität zu erhalten):

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); 
    } 
} 

Dann können Sie die Methode, wie so nennen:

@Html.CheckBoxFor(t => t.boolValue, new { disabled="disabled" }, false) 
+0

Ich habe nicht Ihre genaue Implementierung verwendet, aber Ihre Antwort hat mich auf den Pfad eines benutzerdefinierten Checkbox-Helfers gesetzt. –