CheckBoxFor neden ek bir giriş etiketi oluşturur ve FormCollection kullanarak değeri nasıl alabilirim?


130

ASP.NET MVC uygulamamda, aşağıdaki kodu kullanarak bir onay kutusu oluşturuyorum:

<%= Html.CheckBoxFor(i=>i.ReceiveRSVPNotifications) %>

Şimdi, bunun hem onay kutusu giriş etiketini hem de gizli bir giriş etiketini oluşturduğunu görüyorum . Yaşadığım sorun, FormCollection kullanarak değeri onay kutusundan almayı denediğimde:

FormValues["ReceiveRSVPNotifications"]

"Doğru, yanlış" değerini alıyorum. Oluşturulan HTML'ye baktığımda şunları görebiliyorum:

 <input id="ReceiveRSVPNotifications" name="ReceiveRSVPNotifications" value="true" type="checkbox">
 <input name="ReceiveRSVPNotifications" value="false" type="hidden">

Dolayısıyla, FormValues ​​koleksiyonu aynı ada sahip oldukları için bu iki değeri birleştiriyor gibi görünüyor.

Herhangi bir fikir?

Yanıtlar:


168

Buraya bir göz atın:

http://forums.asp.net/t/1314753.aspx

Bu bir hata değildir ve aslında Ruby on Rails ve MonoRail'in kullandığı yaklaşımla aynıdır.

Onay kutusu içeren bir form gönderdiğinizde, değer yalnızca onay kutusu işaretliyse yayınlanır. Bu nedenle, onay kutusunu işaretlemeden bırakırsanız, sunucuya birçok durumda bunun yerine false gönderilmesini istediğinizde hiçbir şey gönderilmeyecektir. Gizli giriş, onay kutusuyla aynı ada sahip olduğundan, onay kutusu işaretlenmemişse, yine de sunucuya bir 'yanlış' gönderilecektir.

Onay kutusu işaretlendiğinde, ModelBinder otomatik olarak "doğru" yu "doğru, yanlış" dan ayıklamakla ilgilenir.


10
Bu iyi bir açıklamadır, ancak bazı durumlarda ckecbox işaretlenmediğinde sorgu dizesinde 'hiçbir şey' almak isteyebilirsiniz - yani varsayılan davranış. Html yardımcısını kullanarak bu mümkün mü yoksa sadece <input>etiketi kullanmam mı gerekiyor ?
Maksymilian Majer

13
Bundan hoşlanmadım .... GET kullanan bir arama sayfam var ve şimdi url'm doğru / yanlış parametrelerle dolu ...
Shawn Mclean

1
Vay canına, bu beklenmedik. Bu, HTML onay kutusunun aslında "bozuk" olduğu anlamına mı geliyor?
Isantipov

1
@Isantipov: Hayır, bu sadece bu web çerçevelerinin bir onay kutusunun göstermesi için yayınlanan bir değerin olmamasına dayanmadığı anlamına geliyor false. RyanJMcGowan'ın aşağıdaki yanıtına bakın: "Gizli bir girdi göndermek, istek gönderildiğinde sayfada onay kutusunun bulunduğunu bilmeyi mümkün kılar."
Robert Harvey

1
Peki @Robert, bu benim için çalışmıyor. Chbox MyCheckbox işaretli değilse o zaman yanlış alırım, MyCheckbox işaretlendiğinde değeri olarak [true, false] dizisi alırım. Tüm formu serileştiriyorum ve ajax aracılığıyla denetleyici eylemine geçiriyorum örn. AddToOrder (MyModel modeli) burada model.MyCheckbox = true yerine false
nickornotto

18

Shawn'la aynı sorunu yaşadım (yukarıda). Bu yaklaşım POST için harika olabilir, ancak GET için gerçekten berbat. Bu nedenle, gizli alanı kamçılayan basit bir Html uzantısı uyguladım.

public static MvcHtmlString BasicCheckBoxFor<T>(this HtmlHelper<T> html, 
                                                Expression<Func<T, bool>> expression,
                                                object htmlAttributes = null)
{
    var result = html.CheckBoxFor(expression).ToString();
    const string pattern = @"<input name=""[^""]+"" type=""hidden"" value=""false"" />";
    var single = Regex.Replace(result, pattern, "");
    return MvcHtmlString.Create(single);
}

Şu anda sahip olduğum sorun, kodumu kırmak için MVC çerçevesinde bir değişiklik istememem. Bu nedenle, bu yeni sözleşmeyi açıklayan bir test kapsamım olduğundan emin olmalıyım.


5
Sadece bir onay kutusu girişi oluşturmak yerine, gizli girişi eşleştirmek / kaldırmak için normal ifadeyi kullandığın için kendini biraz kirli hissetmiyor musun ? :)
Tim Hobbs

2
Hayır, kendi davranışımı yeniden uygulamak yerine mevcut davranışı düzeltmek için yaptım. Bu şekilde benim değişikliğim, MS'nin sunduğu herhangi bir değişikliğe ayak uyduracaktı.
Chris Kemp

10
Sadece küçük bir gözlem. Uygulamanız, aktarılan hiçbir özel özelliği oluşturmayacaktır. "HtmlAttributes" parametresi, orijinal "CheckBoxFor" yöntemine aktarılmaz.
Emil Lundin

16

GET formları için onay kutularını oluşturmak için bu alternatif yöntemi kullanıyorum:

/// <summary>
/// Renders checkbox as one input (normal Html.CheckBoxFor renders two inputs: checkbox and hidden)
/// </summary>
public static MvcHtmlString BasicCheckBoxFor<T>(this HtmlHelper<T> html, Expression<Func<T, bool>> expression, object htmlAttributes = null)
{
    var tag = new TagBuilder("input");

    tag.Attributes["type"] = "checkbox";
    tag.Attributes["id"] = html.IdFor(expression).ToString();
    tag.Attributes["name"] = html.NameFor(expression).ToString();
    tag.Attributes["value"] = "true";

    // set the "checked" attribute if true
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    if (metadata.Model != null)
    {
        bool modelChecked;
        if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked))
        {
            if (modelChecked)
            {
                tag.Attributes["checked"] = "checked";
            }
        }
    }

    // merge custom attributes
    tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));

    var tagString = tag.ToString(TagRenderMode.SelfClosing);
    return MvcHtmlString.Create(tagString);
}

Chris Kemp'in iyi çalışan yöntemine benziyor , ancak bunun altında yatan ve kullanmıyor . Orijinal yöntemin kaynağına dayanmaktadır .CheckBoxForRegex.ReplaceHtml.CheckBoxFor


Bu kesinlikle bu soruna en iyi çözüm ve MVC çerçevesinin bir parçası olmalı ... mükemmel çalışıyor. Cevabınızın neden daha fazla ilgi görmediğinden emin değilim ... teşekkürler!
user2315985

@ user2315985: Biraz geç gönderdim;) nedeni bu.
Tom Pažourek

Koleksiyon özelliklerini nasıl işliyorsunuz? Varsayılan model bağlayıcı, bağlı dizinlerdeki bir boşlukla karşılaştığında değerleri bağlamayı durdurur, bu nedenle uzantınızı kullanıyormuşsunuz gibi görünür, örneğin, ilk ve son değerler kontrol edildiyse, almanız gereken ikinci değeri asla bilemezsiniz. . Yoksa bir şey mi kaçırıyorum?
Tieson T.

@TiesonT. Kendi model bağlayıcınızı yazmak istemiyorsanız, tek çözüm boşlukları önlemektir. Bu yöntem, işaretlenmemiş onay kutuları için false göndermez, bu nedenle, bunu yapan orijinal Html.CheckBoxFor yöntemini kullanmak isteyebilirsiniz.
Tom Pažourek

10

Ek giriş etiketi için kaynak kodu burada . Microsoft, bunu tam olarak ele alan yorumları dahil etme nezaketini gösterdi.

if (inputType == InputType.CheckBox)
{
    // Render an additional <input type="hidden".../> for checkboxes. This
    // addresses scenarios where unchecked checkboxes are not sent in the request.
    // Sending a hidden input makes it possible to know that the checkbox was present
    // on the page when the request was submitted.
    StringBuilder inputItemBuilder = new StringBuilder();
    inputItemBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing));

    TagBuilder hiddenInput = new TagBuilder("input");
    hiddenInput.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
    hiddenInput.MergeAttribute("name", fullName);
    hiddenInput.MergeAttribute("value", "false");
    inputItemBuilder.Append(hiddenInput.ToString(TagRenderMode.SelfClosing));
    return MvcHtmlString.Create(inputItemBuilder.ToString());
}

9

En basit çözümün INPUT elemanını direk olarak şu şekilde render etmek olduğunu düşünüyorum:

<input type="checkbox" 
       id="<%=Html.IdFor(i => i.ReceiveRSVPNotifications)%>"
       name="<%=Html.NameFor(i => i.ReceiveRSVPNotifications)%>"
       value="true"
       checked="<%=Model.ReceiveRSVPNotifications ? "checked" : String.Empty %>" />

Razor sözdiziminde bu daha da kolaydır, çünkü "işaretli" özniteliği "gerçek" bir sunucu tarafı değeri verildiğinde doğrudan "işaretli" bir değerle işlenir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.