How do I use a SelectListItem in ASP.NET MVC to display choices via a List Box or Check List box

时间:2016-04-21 21:49:55

标签: asp.net-mvc selectlistitem html.listboxfor

I've been reading several articles about how to present choices to users. Some use ListBoxFor, some use CheckBoxFor, and then there is this thing called MultiSelectList.

What I am (was) confused about was that each example seemed to have done it a totally different way, and none of them actually used the built in "SelectListItem" class but instead always created their own.

So I originally was going to post a question asking for general clarification, but I thought it would just be representative of all the other various post and repetitive.

So let me re-phrase: How do you use a "List" or a "MultiSelectList" to present a user a list of choices, including the option for them to be displayed as a list of Check boxes?

In other words, if I have the following 2 items in my Model, how would I display each of them as a typical choice list box, or a typical Check List box?

public List<SelectListItem> Widgets1 { get; set; }
public MultiSelectList Widgets2 { get; set; }

2 个答案:

答案 0 :(得分:0)

警告...只是想指出一旦你有太多选择,“CheckBox”选项基本上会挂起。 (例如,将我的循环更改为500),它基本上不会提交。

问题可以追溯到CheckBoxFor线的验证。这可以通过将一行更改为...来修复。

                        @Html.CheckBoxFor(cc => cc.WidgetsAsCheckList[myIndex].Selected, new { data_val = "false",  htmlAttributes = new { @class = "form-control" } })

如果我这样做,我可以在核对清单中有1,500个项目,提交时间不到3秒

答案 1 :(得分:-1)

So let's start with the Model. It is really basic and you can see that I'm just creating 3 Lists that will store the same data.

The primary difference here is that all of the examples I read, people where creating their own Item classes, where I wanted to simply use the built in "SelectListItem" class

public class FooModel
{
  [Display(Name = "WidgetCheckList")]
  public List<SelectListItem> WidgetsAsCheckList { get; set; }

  [Display(Name = "WidgetListBox")]
  public List<SelectListItem> WidgetsAsListBox { get; set; }

  [Display(Name = "WidgetMultiSelectList")]
  public MultiSelectList WidgetMultiSelectList { get; set; }

  //We have to create a bucket that not only some how 
  //auto-magically knowns what has been pre-selected in the 
  //original list, but provides the view something to store
  //the new selections in when returning to the controller.
  //I have to admit, I have no idea how this knows what was
  //pre-selected, but being new at MVC, there are things I 
  //just have to leave it as a mystery becuase it just works.

  [HiddenInput(DisplayValue = false)]
  public List<string> userSelectionsAsListBox { get; set; }

  [HiddenInput(DisplayValue = false)]
  public List<string> userSelectionsAsMultiSelectList { get; set; }

  public FooModel()
  {
    this.WidgetsAsCheckList = new List<SelectListItem>();
    this.WidgetsAsListBox = new List<SelectListItem>();
    this.WidgetMultiSelectList = new MultiSelectList(new List<SelectListItem>());
  }
}   

For the Controller, because this was a learning test, I just made up the data. The key here is that I build a List of SelectListItems and then used that same list to populate all 3 demo fields of the Model to show 3 different ways to work with the same data.

// ------------------------------------------------------------------------
[HttpGet]       //Display the Edit view
public ActionResult Edit()
{
    FooModel myModel = new FooModel;

    //For testing, here I'm going to Inject some Choices
    //So first we build a list of them
    List<SelectListItem> myChoices = new List<SelectListItem>();
    for (Int32 myIndex = 1; myIndex < 15; myIndex++)
    {
        SelectListItem myChoice = new SelectListItem();
        myChoice.Value = myIndex.ToString();
        myChoice.Text = "Choice " + myIndex.ToString();
        if ((myIndex % 2) == 0)
        {
            myChoice.Selected = true;
        }
        else
        {
            myChoice.Selected = false;
        }
        myChoices.Add(myChoice);
    }

    String[] mySelections = myChoices.Where(x => x.Selected == true).ToArray().Select(x => x.Value).ToArray();

    //Now we use that same list to populate all 3 variations in our model
    myModel.WidgetsAsCheckList.AddRange(myChoices);
    myModel.WidgetsAsListBox.AddRange(myChoices);
    myModel.WidgetMultiSelectList = new MultiSelectList(myChoices, "Value", "Text", mySelections); 

    return View(myModel);
}

Now for the view, I display each list. The first of course is a check box and the second and third are list boxes but use different underlying objects...

@* This displays the "list" of SelectListItems as Checkboxes but we have to do alot more work *@
<div class="form-group">
    @Html.LabelFor(model => model.WidgetsAsCheckList, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        <div class="form-control" style="overflow-y: scroll; height: 25em; width:280px;">
            @for (var myIndex = 0; myIndex < Model.WidgetsAsCheckList.Count; myIndex++)
            {
                @Html.CheckBoxFor(cc => cc.WidgetsAsCheckList[myIndex].Selected, new { htmlAttributes = new { @class = "form-control" } })
                @Html.HiddenFor(cc => cc.WidgetsAsCheckList[myIndex].Value, new { htmlAttributes = new { @class = "form-control" } })
                @Html.DisplayFor(cc => cc.WidgetsAsCheckList[myIndex].Text, new { htmlAttributes = new { @class = "form-control" } })
                <br />
            }
        </div>
    </div>

</div>

 @* This displays the "list" of SelectListItems as list box that does all the work for us *@
<div class="form-group">
    @Html.LabelFor(model => model.WidgetsAsListBox, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">                
        @Html.ListBoxFor(model => model.userSelectionsAsListBox, Model.WidgetsAsListBox, new { @class = "form-control", size = 25 })
    </div>
</div>

@* This displays the "MultiSelectList" as list box that does all the work for us *@
<div class="form-group">
    @Html.LabelFor(model => model.WidgetMultiSelectList, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.ListBoxFor(model => model.userSelectionsAsMultiSelectList, Model.WidgetMultiSelectList, new { @class = "form-control", size = 25 })
    </div>
</div>

And finally, when the user makes their own selections (or takes the pre-selected ones) and hits submit, we can get the results in the the controller simply by...

// ---------------------------------------------------------------------
[HttpPost]       
[ValidateAntiForgeryToken]
public ActionResult Edit(FooModel myFooModel)
{

    List<string> SelectedItemsFromListBox = myFooModel.userSelectionsAsListBox;

    List<string> SelectedItemsFromMultiSelectList = myFooModel.userSelectionsAsMultiSelectList;

    List<string> SelectedItemsFromCheckList = myFooModel.WidgetsAsCheckList.Where(x => x.Selected == true).ToList().Select(x => x.Value).ToList();

}