Hộp kiểm cho boolean nullable


97

Mô hình của tôi có boolean phải là nullable

public bool? Foo
{
   get;
   set;
}

vì vậy trong cshtml Razor của tôi, tôi có

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

ngoại trừ điều đó không hoạt động. Không truyền nó với (bool). Nếu tôi làm

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

điều đó không tạo ra lỗi, nhưng nó không liên kết với mô hình của tôi khi được đăng và foo được đặt thành null. Cách tốt nhất để hiển thị Foo trên trang và làm cho nó liên kết với mô hình của tôi trên một bài đăng?



2
Luồng đó bỏ qua vấn đề, rằng tôi phải có thể phát hiện null là giá trị thứ ba. Một lần gửi biểu mẫu không chọn hộp kiểm và một lần gửi biểu mẫu không hiển thị hộp kiểm là hai tình huống khác nhau phải được tính đến.
DMulligan

Câu trả lời:


107

Tôi có nó để làm việc với

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

và sau đó tạo Boolean.cshtml trong thư mục EditorTemplates của tôi và dán

@model bool?

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

phía trong.


2
Làm việc cho tôi. Cảm ơn!
Samuel

1
Trong khi làm việc với các kiểu boolean có thể nullable, tôi đã sử dụng cái này '' @ Html.CheckBoxFor (m => m.Foo.HasValue) ''
Gaurav Aroraa 8/10/14

9
@GauravKumarArora Bạn đang tạo một hộp kiểm cho thuộc tính nullable HasValue, nhưng không phải giá trị boolean thực. Thao tác này sẽ tạo một hộp kiểm được chọn nếu bất kể giá trị cơ bản là gì. Nếu nullable có một giá trị, nó sẽ luôn đúng.
Siewers

1
Đây chắc chắn là giải pháp linh hoạt và sạch sẽ của trang này. +1
T-moty

2
chỉ là một lưu ý: 1. Bạn có để lưu trữ tập tin này trong "Views / Shared / EditorTemplates" 2. bạn phải đặt tên tập tin này "Boolean.cshtml"
Jarrette

46

Đã tìm thấy câu trả lời trong câu hỏi tương tự - Hiển thị Nullable Bool dưới dạng CheckBox . Nó rất đơn giản và chỉ hoạt động:

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

Nó giống như câu trả lời được chấp nhận từ @afinkelstein ngoại trừ chúng tôi không cần 'mẫu trình chỉnh sửa' đặc biệt


1
Ưu điểm khác của điều này so với câu trả lời được chấp nhận là bạn có thể quyết định xem null nên tương đương với true hay false trên cơ sở từng trường hợp do logic ứng dụng của bạn quy định, thay vì có một mặc định duy nhất trong toàn bộ ứng dụng (hoặc tạo hai trình soạn thảo mẫu!).
ChrisFox

25

Tôi có bool? IsDisabled { get; set; }trong Model. Đã chèn nếu trong Chế độ xem.

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

1
Không tốt lắm vì bạn thay đổi giá trị trong mô hình và trong nhiều trường hợp, false không bằng null. Tôi đã cho bạn một điểm vì đây là một thử nghiệm hay. Lưu ý rằng tôi cũng đồng ý với Darin :)
Samuel

7
Không nên cho điểm vì đây là một thử hay vì nó có thể chỉ ra không chính xác cho những người đọc khác rằng câu trả lời hữu ích khi nó có vấn đề.
Chris

Một giải pháp thay thế đẹp hơn là đặt Boolean thành false trong bộ điều khiển nếu null trước khi hiển thị trang, nhưng vẫn sử dụng ý tưởng .Value.
Graham Laight

15

Mô hình của tôi có boolean phải là nullable

Tại sao? Điều này không có ý nghĩa. Hộp kiểm có hai trạng thái: được chọn / không được chọn hoặc Đúng / Sai nếu bạn muốn. Không có trạng thái thứ ba.

Hay đợi bạn đang sử dụng các mô hình miền của mình trong các chế độ xem thay vì các mô hình xem? Đó là vấn đề của bạn. Vì vậy, giải pháp cho tôi là sử dụng một mô hình chế độ xem trong đó bạn sẽ xác định một thuộc tính boolean đơn giản:

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

và bây giờ bạn sẽ có hành động của bộ điều khiển chuyển mô hình chế độ xem này đến chế độ xem và tạo hộp kiểm thích hợp.


26
Có vô số lý do khác nhau khiến đầu vào foo có thể không xuất hiện trên trang. Nếu nó xuất hiện, tôi có thể cho rằng có một giá trị, nhưng tôi cần phân biệt được thời điểm mô hình được đăng với foo là không được chọn và khi nào foo không được hiển thị.
DMulligan

@KMulligan, còn việc bao gồm một thuộc tính boolean khác trên mô hình chế độ xem của bạn cho biết liệu bạn có nên hiển thị hộp kiểm cho thuộc tính Foo hay không và hộp kiểm này có thể được lưu trữ trong một trường ẩn để khi đăng lại, bạn sẽ biết mình có nên tính đến giá trị Foo không hay không.
Darin Dimitrov

Tôi đã làm điều đó ban đầu, nhưng tôi nhận được rất nhiều loại giá trị ban đầu có thể có hoặc có thể không được đưa vào biểu mẫu của tôi vì nhiều lý do khác nhau. Thêm boolean cho tất cả chúng bắt đầu cảm thấy ngớ ngẩn. Khi tôi googled nullables, tôi nhận ra đó là cách để đi.
DMulligan

4
@KMulligan, bạn có thể viết helpers, editor template, ... để không phải lặp lại điều này cho mọi thuộc tính có thuộc tính như vậy.
Darin Dimitrov

25
@DarinDimitrov, bạn rõ ràng đã bỏ qua hoặc bỏ qua sự thật rằng OP nói rằng anh ta phải có khả năng đại diện cho khía cạnh "null" của bool. Bạn đã bị treo lên vì anh ấy muốn sử dụng CheckBoxFor. Thay vì nói với anh ta rằng anh ta đã viết "mã xấu" vì anh ta đã sử dụng mô hình miền của mình (mà anh ta có thể đã làm hoặc có thể KHÔNG) và nói với anh ta rằng các hộp kiểm được chọn hoặc bỏ chọn, bạn nên cố gắng trả lời câu hỏi của anh ta hoặc không được trả lời.
Andrew Steitz

7

Việc phức tạp hóa một nguyên thủy với các trường ẩn để làm rõ liệu Sai hay Null không được khuyến khích.

Hộp kiểm không phải là thứ bạn nên sử dụng - nó thực sự chỉ có một trạng thái: Đã kiểm tra . Nếu không, nó có thể là bất cứ điều gì.

Khi trường cơ sở dữ liệu của bạn là boolean có thể null ( bool?), UX phải sử dụng 3-Radio Buttons, trong đó nút đầu tiên đại diện cho "Đã kiểm tra" của bạn, nút thứ hai đại diện cho "Chưa kiểm tra" và nút thứ ba đại diện cho null của bạn, bất kể ngữ nghĩa của null nghĩa là. Bạn có thể sử dụng <select><option>danh sách thả xuống để lưu bất động sản, nhưng người dùng phải nhấp hai lần và các lựa chọn gần như không rõ ràng ngay lập tức.

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

RadioButtonList, được định nghĩa là phần mở rộng có tên RadioButtonForSelectList, xây dựng các nút radio cho bạn, bao gồm giá trị đã chọn / đã chọn và đặt <div class="RBxxxx"> để bạn có thể sử dụng css để làm cho các nút radio của bạn nằm ngang (hiển thị: inline-block), dọc hoặc theo kiểu bảng (display: inline-block; width: 100px;)

Trong mô hình (Tôi đang sử dụng chuỗi, chuỗi cho định nghĩa từ điển làm ví dụ sư phạm. Bạn có thể sử dụng 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

Đối với tôi, giải pháp là thay đổi mô hình chế độ xem. Coi như bạn đang tìm kiếm hóa đơn. Các hóa đơn này có thể được thanh toán hoặc không. Vì vậy, tìm kiếm của bạn có ba tùy chọn: Trả phí, Không trả tiền hoặc "Tôi không quan tâm".

Tôi đã có điều này ban đầu được thiết lập như một bool? cánh đồng:

public bool? PaidInvoices { get; set; }

Điều này khiến tôi vấp phải câu hỏi này. Cuối cùng tôi đã tạo một loại Enum và tôi xử lý điều này như sau:

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

Tất nhiên tôi đã gói chúng trong nhãn và có văn bản được chỉ định, ý tôi là đây là một lựa chọn khác để xem xét.


Đây là một đại diện hữu ích. Nếu bạn có không gian hạn chế, bạn cũng có thể đạt được điều này với trình đơn thả xuống / chọn, ngoại trừ việc phải mất hai lần nhấp để chọn một tùy chọn. Như với các lựa chọn, các nút radio có thể trông rất khác nhau giữa các trình duyệt, có thể là một nhà thiết kế.
Savage

4

Hộp kiểm chỉ cung cấp cho bạn 2 giá trị (đúng, sai). Nullable boolean có 3 giá trị (true, false, null) nên không thể thực hiện được với hộp kiểm.

Một lựa chọn tốt là sử dụng trình đơn thả xuống để thay thế.

Mô hình

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

Bộ điều khiển

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

Lượt xem

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

1
Nếu bạn không quan tâm đến việc người dùng có thể đặt cả 3 giá trị có thể có, thì bạn không thể đại diện cho cả 3 chỉ bằng một hộp kiểm.
Dave

@Dave Tôi nghĩ bạn đã hoàn toàn bỏ sót ý. OP có bool? nghĩa là anh ta cần chọn một trong 3 giá trị có thể. Nếu anh ta muốn chỉ có đúng hoặc sai, anh ta nên sử dụng bool chứ không phải bool?
Gudradain

1
Trên thực tế, nhận xét của OP chỉ ra điều ngược lại - rằng nếu có một hộp kiểm trong biểu mẫu, anh ta không muốn null là một tùy chọn, bởi vì tùy chọn đó bị che khi có một biểu mẫu khác không có hộp kiểm.
Dave

Tôi đã sử dụng cùng một chiến lược này trong một trang tìm kiếm. Bạn có thể tìm kiếm Có, Không hoặc bỏ qua boolean trong tìm kiếm của mình. Có một trường hợp sử dụng! : D
Jess

4

Tôi thực sự sẽ tạo một mẫu cho nó và sử dụng mẫu đó với một EditorFor ().

Đây là cách tôi đã làm điều đó:

  1. Tạo mẫu của tôi, về cơ bản là dạng xem một phần mà tôi đã tạo trong thư mục EditorTemplates, trong mục Được chia sẻ, bên dưới Chế độ xem đặt tên nó là (ví dụ) 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. Sử dụng nó như thế này (trong mọi góc nhìn):

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

Đó là tất cả.

Mẫu rất mạnh trong MVC, hãy sử dụng chúng .. Bạn có thể tạo toàn bộ trang dưới dạng mẫu, mà bạn sẽ sử dụng với @Html.EditorFor(); với điều kiện bạn chuyển mô hình xem của nó trong biểu thức lambda ..


3

Cách tiếp cận rõ ràng nhất mà tôi có thể đưa ra là mở rộng các tiện ích mở rộng có sẵn HtmlHelpertrong khi vẫn sử dụng lại chức năng được cung cấp bởi khuôn khổ.

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

Tôi đã thử nghiệm với việc 'định hình' biểu thức để cho phép truyền thẳng đến người bản địa CheckBoxFor<Expression<Func<T, bool>>>nhưng tôi không nghĩ là có thể.


Tôi đã phải thay đổi chữ ký của phương pháp để điều này phù hợp với tôi: Tôi đã sử dụng public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes)và nó hoạt động tuyệt vời.
Pierre-Loup Pagniez

1

Tôi đã có một vấn đề tương tự trong quá khứ.

Tạo đầu vào Hộp kiểm trong HTML và đặt tên thuộc tính = "Foo" Điều này vẫn sẽ đăng đúng cách.

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

Điều này dường như không được đăng, tôi vẫn nhận được vô hiệu.
DMulligan

2
Điều này có thể có vấn đề với các mô hình liên kết
halb Yoel

0

Chỉ cần kiểm tra giá trị null và trả về giá trị false:

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

Bạn biết rằng siêu dữ liệu thuộc tính của bạn sẽ bị mất, phải không? Xác thực phía máy khách, tên trường và id, v.v.
T-moty

0

Tôi cũng phải đối mặt với vấn đề tương tự. Tôi đã thử cách tiếp cận sau để giải quyết vấn đề vì tôi không muốn thay đổi DB và tạo lại EDMX.

@{

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

 }

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

0

Khi tạo một EditorTemplate cho một mô hình chứa bool có thể nullable ...

  • Chia bool nullable thành 2 boolean:

    // 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; }
  • Trong mẫu trình chỉnh sửa:

    @Html.HiddenFor(m => m.FooIsNull)
    
    @if (Model.FooIsNull)
    {
        // Null means "checkbox is hidden"
        @Html.HiddenFor(m => m.FooCheckbox)
    }
    else
    {
        @Html.CheckBoxFor(m => m.FooCheckbox)
    }
  • Không đăng lại thuộc tính ban đầu Foo, vì điều đó hiện được tính từ FooIsNull và FooCheckbox.


0

Tất cả các câu trả lời ở trên đi kèm với các vấn đề riêng của nó. Cách dễ nhất / sạch nhất IMO là tạo một người trợ giúp

MVC5 Razor

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

Sử dụng

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

Trong kịch bản của tôi, một phương tiện checkbox nullable rằng một nhân viên vẫn chưa hỏi những câu hỏi cho khách hàng, vì vậy nó được bọc trong một .checkbox-nullableđể bạn có thể phong cách phù hợp và giúp người dùng cuối xác định rằng nó không phải là truehayfalse

CSS

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

0

Các phương pháp mở rộng:

        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

Các nút radio rất hữu ích, nhưng chúng không cho phép bạn bỏ chọn . Nếu bạn muốn hành vi này, hãy xem xét sử dụng trình đơn thả xuống / chọn. Đoạn mã sau sẽ tạo SelectListvà điều này liên kết thành công với một boolean 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
điều này sẽ ném ra một ngoại lệ nếu testVar là null.
danwyand 14/09/15

-1

bạn có thể thử như thế này

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

-4

Đây là một câu hỏi cũ và các câu trả lời hiện có mô tả hầu hết các lựa chọn thay thế. Nhưng có một lựa chọn đơn giản, nếu bạn có bool? trong mô hình xem của bạn và bạn không quan tâm đến null trong giao diện người dùng của mình:

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

2
Bạn đã thử cái này chưa? Vì các phương thức xxxFor mong đợi một biểu thức thành viên, tôi dám cá rằng điều này sẽ tạo ra lỗi thời gian chạy. Nó đang cố gắng xác định thuộc tính hoặc trường mục tiêu, không đánh giá bất cứ thứ gì vào thời điểm này.
JRoughan

2
lỗi thời gian chạy "Mẫu chỉ có thể được sử dụng với quyền truy cập trường, quyền truy cập thuộc tính, chỉ mục mảng một thứ nguyên hoặc biểu thức trình lập chỉ mục tùy chỉnh một tham số."
ePezhman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.