nullable 부울 체크 박스


97

내 모델에는 nullable이어야하는 부울이 있습니다.

public bool? Foo
{
   get;
   set;
}

그래서 내 Razor cshtml에서

@Html.CheckBoxFor(m => m.Foo)

작동하지 않는 것을 제외하고. (bool)로도 캐스팅하지 않습니다. 만약 내가한다면

@Html.CheckBoxFor(m => m.Foo.Value)

그것은 오류를 생성하지 않지만 게시되고 foo가 null로 설정되면 내 모델에 바인딩되지 않습니다. 페이지에 Foo를 표시하고 게시물의 내 ​​모델에 바인딩하는 가장 좋은 방법은 무엇입니까?



2
해당 스레드는 null을 세 번째 값으로 감지 할 수 있어야한다는 문제를 무시합니다. 확인란이 선택되지 않은 양식 제출과 확인란이 표시되지 않은 양식 제출은 고려해야 할 두 가지 시나리오입니다.
DMulligan

답변:


107

나는 그것을 함께 일했다

@Html.EditorFor(model => model.Foo) 

그런 다음 EditorTemplates 폴더에 Boolean.cshtml을 만들고 고정

@model bool?

@Html.CheckBox("", Model.GetValueOrDefault())

내부.


2
나를 위해 작동합니다. 감사!
Samuel

1
nullable 부울 유형으로 작업하는 동안이 '' '@ Html.CheckBoxFor (m => m.Foo.HasValue)' ''를 사용했습니다.
Gaurav Aroraa

9
@GauravKumarArora HasValue실제 부울 값이 아닌 nullable 속성에 대한 확인란을 만들고 있습니다. 기본 값에 관계없이 선택된 확인란이 생성됩니다. nullable에 값이 있으면 항상 true입니다.
Siewers 2015-04-08

1
이것은 확실히이 페이지의 훨씬 깨끗하고 유연한 솔루션입니다. +1
T-moty 2015 년

2
그냥 참고 :이 파일 "Boolean.cshtml"이름을 가지고 2. "보기 / 공유 / EditorTemplates"에서이 파일을 저장해야 1.
Jarrette

46

비슷한 질문 -Rendering Nullable Bool as CheckBox 에서 답변을 찾았습니다 . 매우 간단하고 작동합니다.

@Html.CheckBox("RFP.DatesFlexible", Model.RFP.DatesFlexible ?? false)
@Html.Label("RFP.DatesFlexible", "My Dates are Flexible")

특별한 '편집기 템플릿'이 필요하지 않다는 점을 제외하면 @afinkelstein의 대답과 같습니다.


1
허용되는 답변에 비해 이것의 또 다른 장점은 응용 프로그램 전체에 단일 기본값을 사용하거나 두 개의 편집기를 만드는 대신 응용 프로그램의 논리에 따라 사례별로 null이 true 또는 false인지 여부를 결정할 수 있다는 것입니다. 템플릿!).
ChrisFox

25

나는 bool? IsDisabled { get; set; }모델에 있습니다. 보기에있는 경우 삽입됩니다.

<div class="inputClass" id="disabled">
    <div>
    @if(Model.IsDisabled==null)
    {
        Model.IsDisabled = false;
    }           
    @Html.CheckBoxFor(model => model.IsDisabled.Value)         
    </div>
</div> 

1
모델의 값을 변경하고 많은 경우에 false가 null과 같지 않기 때문에 좋지 않습니다. 좋은 시도이기 때문에 포인트를주었습니다. 나는 또한 : 대린에 동의합니다
사무엘

7
다른 독자들에게 문제가있을 때 답이 유용하다고 잘못 표시 할 수 있으므로 좋은 시도이므로 점수주지 말 것을 권장 합니다.
Chris

더 나은 대안은 페이지를 렌더링하기 전에 null 인 경우 컨트롤러에서 Boolean을 false로 설정하지만 여전히 .Value 아이디어를 사용하는 것입니다.
Graham Laight

15

내 모델에는 nullable이어야하는 부울이 있습니다.

왜? 이건 말이 안 돼. 확인란에는 선택 / 선택 취소 또는 원하는 경우 True / False의 두 가지 상태가 있습니다. 세 번째 상태는 없습니다.

아니면 뷰 모델 대신 뷰에서 도메인 모델을 사용하고 계십니까? 그게 당신 문제입니다. 그래서 나를위한 해결책은 간단한 부울 속성을 정의 할 뷰 모델을 사용하는 것입니다.

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

이제 컨트롤러 작업이이 뷰 모델을 뷰에 전달하고 적절한 확인란을 생성하게됩니다.


26
foo 입력이 페이지에 전혀 나타나지 않는 이유는 무수히 많습니다. 표시되면 값이 있다고 가정 할 수 있지만 모델이 foo가 선택되지 않은 상태로 게시되는시기와 foo가 표시되지 않는시기를 구분할 수 있어야합니다.
DMulligan 2011

@KMulligan, Foo 속성에 대한 확인란을 렌더링해야하는지 여부와 숨겨진 필드에 저장할 수있는 다른 부울 속성을 뷰 모델에 포함하여 포스트 백 할 때 Foo 값을 고려해야하는지 여부를 알 수 있습니다. 또는 아닙니다.
Darin Dimitrov 2011

원래 그렇게했지만 다양한 이유로 내 양식에 포함되거나 포함되지 않을 수있는 이러한 원시 값 유형이 많이 있습니다. 그들 모두에 대해 부울을 추가하면 어리석은 느낌이 들기 시작했습니다. nullables를 검색했을 때 그것이 갈 길이라고 생각했습니다.
DMulligan 2011

4
@KMulligan, 도우미, 편집기 템플릿 등을 작성할 수 있으므로 이러한 속성이있는 모든 속성에 대해이 작업을 반복 할 필요가 없습니다.
Darin Dimitrov 2011

25
@DarinDimitrov, OP가 bool의 "null"측면을 나타낼 수 있어야한다는 사실을 분명히 놓쳤거나 무시했습니다. 그가 CheckBoxFor를 사용하기를 원한다는 사실에 당신은 끊었습니다. 그가 도메인 모델을 사용했기 때문에 "잘못된 코드"를 작성했다고 말하고 (그가하지 않았을 수도 있음) 체크 박스가 선택되어 있거나 선택되어 있지 않다고 말하는 대신, 그의 질문에 답을 시도했거나 응답하지 않았어야했습니다.
Andrew Steitz

7

False 또는 Null이 권장되지 않는지 여부를 명확히하기 위해 숨겨진 필드로 기본 요소를 복잡하게 만듭니다.

Checkbox는 사용해야하는 것이 아닙니다. 실제로 Checked 상태 만 있습니다 . 그렇지 않으면 무엇이든 될 수 있습니다.

데이터베이스 필드가 nullable 부울 ( bool?)이면 UX는 3-Radio Buttons를 사용해야합니다. 여기서 첫 번째 버튼은 "Checked", 두 번째 버튼은 "Not Checked", 세 번째 버튼은 null을 나타냅니다. null은 의미합니다. <select><option>드롭 다운 목록을 사용하여 부동산을 절약 할 수 있지만 사용자는 두 번 클릭해야하며 선택 사항이 거의 즉시 명확하지 않습니다.

  1     0      null 
True  False  Not Set
Yes   No     Undecided
Male  Female Unknown
On    Off    Not Detected

RadioButtonForSelectList라는 확장명으로 정의 된 RadioButtonList는 선택 / 확인 된 값을 포함하여 라디오 버튼을 빌드하고 <div class="RBxxxx">CSS를 사용하여 라디오 버튼을 수평 (디스플레이 : 인라인 블록), 수직 또는 테이블 형식으로 (디스플레이 : 인라인 블록; 너비 : 100px;)

모델에서 (저는 문자열, 사전 정의를위한 문자열을 교육적 예제로 사용하고 있습니다. bool ?, string을 사용할 수 있습니다.)

public IEnumerable<SelectListItem> Sexsli { get; set; }
       SexDict = new Dictionary<string, string>()
        {
                { "M", "Male"},
                { "F", "Female" },
                { "U", "Undecided" },

        };

        //Convert the Dictionary Type into a SelectListItem Type
        Sexsli = SexDict.Select(k =>
              new SelectListItem
              {
                  Selected = (k.Key == "U"),
                  Text = k.Value,
                  Value = k.Key.ToString()
              });

<fieldset id="Gender">
<legend id="GenderLegend" title="Gender - Sex">I am a</legend>
    @Html.RadioButtonForSelectList(m => m.Sexsli, Model.Sexsli, "Sex") 
        @Html.ValidationMessageFor(m => m.Sexsli)
</fieldset>

public static class HtmlExtensions
{
public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> expression,
    IEnumerable<SelectListItem> listOfValues,
    String rbClassName = "Horizontal")
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var sb = new StringBuilder();

if (listOfValues != null)
{
    // Create a radio button for each item in the list 
    foreach (SelectListItem item in listOfValues)
    {
        // Generate an id to be given to the radio button field 
        var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);

        // Create and populate a radio button using the existing html helpers 
        var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));

        var radio = String.Empty;

        if (item.Selected == true)
        {
            radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id, @checked = "checked" }).ToHtmlString();
        }
        else
        {
            radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();

        }// Create the html string to return to client browser
        // e.g. <input data-val="true" data-val-required="You must select an option" id="RB_1" name="RB" type="radio" value="1" /><label for="RB_1">Choice 1</label> 

        sb.AppendFormat("<div class=\"RB{2}\">{0}{1}</div>", radio, label, rbClassName);
    }
}

return MvcHtmlString.Create(sb.ToString());
}
}

4

저에게 해결책은 뷰 모델을 변경하는 것이 었습니다. 송장을 검색하고 있다고 생각해보십시오. 이 송장은 지불하거나 지불하지 않을 수 있습니다. 따라서 검색에는 유료, 미지급 또는 "상관 없음"의 세 가지 옵션이 있습니다.

원래 bool로 설정 했습니까? 들:

public bool? PaidInvoices { get; set; }

이것은 나를이 질문에 비틀 거리게 만들었다. 결국 Enum 유형을 만들고 다음과 같이 처리했습니다.

@Html.RadioButtonFor(m => m.PaidInvoices, PaidStatus.NotSpecified, new { @checked = true })
@Html.RadioButtonFor(m => m.PaidInvoices, PaidStatus.Yes) 
@Html.RadioButtonFor(m => m.PaidInvoices, PaidStatus.No)

물론 라벨로 감싸고 텍스트를 지정했습니다. 고려해야 할 또 다른 옵션이 있습니다.


이것은 유용한 표현입니다. 공간이 제한된 경우 드롭 다운 / 선택을 사용하여이 작업을 수행 할 수도 있습니다. 단 두 번의 클릭으로 옵션을 선택할 수 있습니다. 선택과 마찬가지로 라디오 버튼은 브라우저마다 매우 다르게 보일 수 있으며 이는 디자이너 지옥 일 수 있습니다.
Savage

4

체크 박스는 2 개의 값 (true, false) 만 제공합니다. Nullable 부울에는 3 개의 값 (true, false, null)이 있으므로 확인란으로 수행 할 수 없습니다.

좋은 옵션은 드롭 다운을 대신 사용하는 것입니다.

모델

public bool? myValue;
public List<SelectListItem> valueList;

제어 장치

model.valueList = new List<SelectListItem>();
model.valueList.Add(new SelectListItem() { Text = "", Value = "" });
model.valueList.Add(new SelectListItem() { Text = "Yes", Value = "true" });
model.valueList.Add(new SelectListItem() { Text = "No", Value = "false" });

전망

@Html.DropDownListFor(m => m.myValue, valueList)

1
사용자가 3 개의 가능한 값을 모두 설정할 수 있는지에 대해 신경 쓰지 않는다면 확인란 만 사용하여 3 개를 모두 나타낼 수는 없습니다.
Dave

@Dave 나는 당신이 요점을 완전히 놓친 것 같습니다. OP에 부울이 있습니까? 3 가지 가능한 값 중 하나를 선택해야한다는 의미입니다. 그가 참 또는 거짓 만 갖고 싶다면 부울이 아닌 부울을 사용해야합니까?
Gudradain 2014 년

1
실제로 OP의 주석은 그 반대를 나타냅니다. 양식에 확인란이 있으면 해당 옵션이 확인란이없는 다른 양식이있을 때 해당 옵션이 적용되기 때문에 그는 null이 옵션이되는 것을 전혀 원하지 않습니다.
Dave

검색 페이지에서 이와 동일한 전략을 사용했습니다. Yes, No를 검색하거나 검색에서 부울을 무시할 수 있습니다. 이 유스 케이스가! : D
Jess

4

실제로 템플릿을 만들고 EditorFor ()와 함께 해당 템플릿을 사용합니다.

내가 한 방법은 다음과 같습니다.

  1. 기본적으로 EditorTemplates 디렉토리의 Shared, Views 아래에서 만든 부분보기 인 내 템플릿 만들기 : 이름을 (예 :) CheckboxTemplate:

    @using System.Globalization    
    @using System.Web.Mvc.Html    
    @model bool?
    
    @{
        bool? myModel = false;
        if (Model.HasValue)
        {
            myModel = Model.Value;
        }
    }
    
    <input type="checkbox" checked="@(myModel)" name="@ViewData.TemplateInfo.HtmlFieldPrefix" value="True" style="width:20px;" />
  2. 다음과 같이 사용하십시오 (모든보기에서).

    @ Html.EditorFor (x => x.MyNullableBooleanCheckboxToBe, "CheckboxTemplate")

그게 다야.

템플릿은 MVC에서 매우 강력하므로 사용합니다. 전체 페이지를 템플릿으로 만들 수 있으며 @Html.EditorFor(); 보기 모델을 람다 식으로 전달하는 경우 ..


3

내가 생각 해낼 수있는 가장 깔끔한 접근 방식 HtmlHelper은 프레임 워크에서 제공하는 기능을 재사용하면서 사용 가능한 확장을 확장하는 것 입니다.

public static MvcHtmlString CheckBoxFor<T>(this HtmlHelper<T> htmlHelper, Expression<Func<T, bool?>> expression, IDictionary<string, object> htmlAttributes) {

    ModelMetadata modelMeta = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    bool? value = (modelMeta.Model as bool?);

    string name = ExpressionHelper.GetExpressionText(expression);

    return htmlHelper.CheckBox(name, value ?? false, htmlAttributes);
}

나는 네이티브에게 똑바로 통과 할 수 있도록 표현을 '모양'하는 실험을 CheckBoxFor<Expression<Func<T, bool>>>했지만 불가능하다고 생각합니다.


이 작업을 수행하려면 메서드의 서명을 변경 public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes)해야했습니다. 사용 했고 훌륭하게 작동했습니다.
Pierre-Loup Pagniez

1

과거에도 비슷한 문제가있었습니다.

HTML로 체크 박스 입력을 생성하고 name = "Foo"속성을 설정합니다. 그래도 제대로 게시되어야합니다.

<input type="checkbox" name="Foo" checked="@model.Foo.Value" /> Foo Checkbox<br />

이것은 게시되지 않는 것 같습니다. 여전히 null이 발생합니다.
DMulligan 2011

2
모델 바인딩에 문제가있을 수 있습니다.
yoel halb 2014-06-19

0

null 값을 확인하고 false를 반환하십시오.

@{ bool nullableValue = ((Model.nullableValue == null) || (Model.nullableValue == false)) ? false : true; }
@Html.CheckBoxFor(model => nullableValue)

자산 메타 데이터가 손실된다는 것을 알고 있습니까? 클라이언트 측 유효성 검사, 필드 이름 및 ID 등
T-moty

0

나도 같은 문제에 직면했습니다. DB를 변경하고 EDMX를 다시 생성하고 싶지 않기 때문에 문제를 해결하기 위해 다음 접근 방식을 시도했습니다.

@{

   bool testVar = (Model.MYVar ? true : false);

 }

<label>@Html.CheckBoxFor(m => testVar)testVar</label><br />

0

nullable bool을 포함하는 모델에 대한 EditorTemplate을 만들 때 ...

  • nullable 부울을 2 개의 부울로 분할합니다.

    // Foo is still a nullable boolean.
    public bool? Foo 
    {
        get 
        { 
            if (FooIsNull)
                return null;
    
            return FooCheckbox;  
        }
        set
        {
            FooIsNull   = (value == null);
            FooCheckbox = (value ?? false);
        }
    }
    
    // These contain the value of Foo. Public only so they are visible in Razor views.
    public bool FooIsNull { get; set; }
    public bool FooCheckbox { get; set; }
  • 편집기 템플릿 내에서 :

    @Html.HiddenFor(m => m.FooIsNull)
    
    @if (Model.FooIsNull)
    {
        // Null means "checkbox is hidden"
        @Html.HiddenFor(m => m.FooCheckbox)
    }
    else
    {
        @Html.CheckBoxFor(m => m.FooCheckbox)
    }
  • 원래 속성 Foo는 이제 FooIsNull 및 FooCheckbox에서 계산되므로 포스트 백하지 마십시오.


0

위의 모든 답변에는 자체 문제가 있습니다. IMO가 도우미를 만드는 가장 쉽고 / 가장 깨끗한 방법

MVC5 면도기

App_Code / Helpers.cshtml

@helper CheckBoxFor(WebViewPage page, string propertyName, bool? value, string htmlAttributes = null)
{
    if (value == null)
    {
        <div class="checkbox-nullable">
            <input type="checkbox" @page.Html.Raw(htmlAttributes)>
        </div>
    }
    else if (value == true)
    {
        <input type="checkbox" value="true" @page.Html.Raw(htmlAttributes) checked>
    }
    else
    {
        <input type="checkbox" value="false" @page.Html.Raw(htmlAttributes)>
    }
}

용법

@Helpers.CheckBoxFor(this, "IsPaymentRecordOk", Model.IsPaymentRecordOk)

에 싸여 그래서 내 시나리오에서는 null 허용 확인란 수단은 아직 클라이언트에 질문을하지 않는 직원이했다고 .checkbox-nullable는도 적절 스타일 및 최종 사용자가인지 식별 할 수 있도록 truefalse

CSS

.checkbox-nullable {
    border: 1px solid red;
    padding: 3px;
    display: inline-block;
}

0

확장 방법 :

        public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression)
        {
            return htmlHelper.CheckBoxFor<TModel>(expression, null);
        }
        public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes)
        {
            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 htmlHelper.CheckBox(ExpressionHelper.GetExpressionText(expression), isChecked??false ,  htmlAttributes);
        }

0

라디오 버튼은 유용하지만을 선택 취소 할 수는 없습니다 . 이 동작을 원하면 드롭 다운 / 선택을 사용하는 것이 좋습니다. 다음 코드는를 생성 SelectList하고 이는 nullable 부울에 성공적으로 바인딩됩니다.

public static SelectList GetBoolTriState()
{
    var items = new List<SelectListItem>
    {
        new SelectListItem {Value = "", Text = ""},
        new SelectListItem {Value = "True", Text = "Yes"},
        new SelectListItem {Value = "False", Text = "No"},
    };

    return new SelectList(items, "Value", "Text");
}

-1
@{  bool testVar = ((bool)item.testVar ? true : false); }
  @Html.DisplayFor(modelItem => testVar)

1
testVar가 null 인 경우 예외가 발생합니다.
danwyand

-1

당신은 이렇게 시도 할 수 있습니다

@Html.TextBoxFor(m => m.foo, new {   type = "checkbox" })

-4

이것은 오래된 질문이며 기존 답변은 대부분의 대안을 설명합니다. 그러나 bool이 있다면 간단한 옵션이 하나 있습니다. 뷰 모델에서 UI에서 null에 대해 신경 쓰지 않습니다.

@Html.CheckBoxFor(m => m.boolValue ?? false);

2
이거 해봤 어? xxxFor 메서드는 멤버 표현식을 기대하기 때문에 이것이 런타임 오류를 생성 할 것이라고 확신합니다. 이 시점에서 아무것도 평가하지 않고 대상 속성 또는 필드를 결정하려고합니다.
JRoughan 2014

2
런타임 오류 "템플릿은 필드 액세스, 속성 액세스, 단일 차원 배열 인덱스 또는 단일 매개 변수 사용자 지정 인덱서 식에만 사용할 수 있습니다."
ePezhman 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.