Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting error at time of binding ListBoxFor control in MVC4

When I am changing the "model => model.id" to "model => model.Supplierid" i am getting below error

"The parameter 'expression' must evaluate to an IEnumerable when multiple selection is allowed."

please have look on below code

// this my model class

public class clslistbox{
public int id { get; set; }
public int Supplierid { get; set; }
public List<SuppDocuments> lstDocImgs { get; set; }

public class SuppDocuments
{
    public string Title { get; set; }
    public int documentid { get; set; }
}
public List<SuppDocuments> listDocImages()
{
    List<SuppDocuments> _lst = new List<SuppDocuments>();
    SuppDocuments _supp = new SuppDocuments();
    _supp.Title = "title";
    _supp.documentid = 1;
    _lst.Add(_supp);
    return _lst;
} 
}

// this my controller

    [HttpGet]
    public ActionResult AddEditSupplier(int id)
    {

        clslistbox _lst = new clslistbox();
        _lst.lstDocImgs= _lst.listDocImages();
        return View(_lst);
    }

// this is view where i am binding listboxfor

@model clslistbox
@using (Html.BeginForm("AddEditSupplier", "Admin", FormMethod.Post))
{
    @Html.ListBoxFor(model => model.id, new SelectList(Model.lstDocImgs, "documentid", "title"))
}

Can anyone see the reason for it?

like image 706
Dotnet Developer Avatar asked Jan 11 '13 09:01

Dotnet Developer


1 Answers

I think the changing of the property in the expression here is a red-herring - it won't work in either case.

Update

However, see at the end of my answer for some probably needlessly detailed exposition on why you didn't get an error first-time round.

End Update

You're using ListBoxFor - which is used to provide users with multiple selection capabilities - but you're trying to bind that to an int property - which cannot support multiple selection. (It needs to be an IEnumerable<T> at least to be able to bind a list box to it by default in MVC)

I think you mean to be using DropDownListFor - i.e. to display a list of items from which only one can be selected?

If you're actually looking for single-selection semantics in a listbox, that's trickier to do in MVC because it's Html helpers are geared entirely around listboxes being for multiple selection. Someone else on SO has asked a question about how to get a dropdown to look like a list box: How do I create a ListBox in ASP.NET MVC with single selection mode?.

Or you could generate the HTML for such a listbox yourself.

(Update) - Potentially needlessly detailed exposition(!)

The reason you don't get an exception first time round is probably because there was no value for id in ModelState when the HTML was generated. Here's the reflected MVC source (from SelectExtensions.SelectInternal) that's of interest (the GetSelectListWithDefaultValue call at the end is the source of your exception):

object obj = 
  allowMultiple ? htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(string[])) : 
    htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(string));
if (!flag && obj == null && !string.IsNullOrEmpty(name))
{
  obj = htmlHelper.ViewData.Eval(name);
}
if (obj != null)
{
  selectList = 
    SelectExtensions.GetSelectListWithDefaultValue(selectList, obj, allowMultiple);
}

Note first that the control variable allowMultiple is true in your case, because you've called ListBoxFor. selectList is the SelectList you create and pass as the second parameter. One of the things that MVC (unfortunately in some cases) does is to use ModelState to modify the select list you pass when re-displaying a view in order to ensure that values which were set in ModelState via a POST are re-selected when the view is reloaded (this is useful when page validation fails because you won't copy the values to your underlying model from ModelState, but the page should still show those values as being selected).

So as you can see on the first line, the model's current value for the expression/field you pass is fished out of model state; either as a string array or as a string. If that fails (returns null)then it makes another go to execute the expression (or similar) to grab the model value. If it gets a non-null value from there, it calls SelectExtensions.GetSelectListWithDefaultValue.

As I say - what you're trying to do will ultimately not work in either the case of Id or SupplierId (because they would need to be IEnumerable) but I believe this ModelState->Eval process is yielding a null value when you use Id, so the process of getting an 'adjusted' SelectList is skipped - so the exception doesn't get raised. The same is not true when you use SupplierId because I'll wager that there's either a value in ModelState at that point, or the ViewData.Eval successfully gets an integer value.

Not throwing an exception is not the same as working!.

End update

like image 56
Andras Zoltan Avatar answered Sep 17 '22 15:09

Andras Zoltan