asp.net-mvc 为什么 ListBoxFor 不选择项目,而 ListBox 是?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2308846/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:09:41  来源:igfitidea点击:

Why is ListBoxFor not selecting items, but ListBox is?

asp.net-mvclistbox

提问by Roger Rogers

I have the following code in my view:

我认为有以下代码:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

<%= Html.ListBox("MultiSelectList", 
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

The only difference is that the first helper is strongly typed (ListBoxFor), and it fails to show the selected items(1,2), even though the items appear in the list, etc. The simpler ListBox is working as expected.

唯一的区别是第一个助手是强类型的 (ListBoxFor),它无法显示所选项目(1,2),即使这些项目出现在列表中,等等。更简单的 ListBox 按预期工作。

I'm obviously missing something here. I can use the second approach, but this is really bugging me and I'd like to figure it out.

我显然在这里遗漏了一些东西。我可以使用第二种方法,但这确实困扰着我,我想弄清楚。

For reference, my model is:

作为参考,我的模型是:

public class ProjectEditModel
{
    public Project Project { get; set; }
    public IEnumerable<Project> Projects { get; set; }
    public IEnumerable<Client> Clients { get; set; }
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Tag> Tags { get; set; }
    public ProjectSlide SelectedSlide { get; set; }
}

Update

更新

I just changed the ListBox name to Project.Categories (matching my model) and it now FAILS to select the item.

我只是将 ListBox 名称更改为 Project.Categories(与我的模型匹配),现在无法选择该项目。

<%= Html.ListBox("Project.Categories",
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

I'm obviously not understanding the magic that is happening here.

我显然不理解这里发生的魔法。

Update 2

更新 2

Ok, this is purely naming, for example, this works...

好吧,这纯粹是命名,例如,这有效...

<%= Html.ListBox("Project_Tags",
new MultiSelectList(Model.Tags, "Id", "Name", Model.Project.Tags.Select(t => t.Id)))%>

...because the field name is Project_Tags, not Project.Tags, in fact, anything other than Tags or Project.Tags will work. I don't get why this would cause a problem (other than that it matches the entity name), and I'm not good enough at this to be able to dig in and find out.

...因为字段名称是 Project_Tags,而不是 Project.Tags,事实上,除了 Tags 或 Project.Tags 之外的任何东西都可以使用。我不明白为什么这会导致问题(除了它与实体名称匹配之外),而且我在这方面还不够好,无法深入研究并找出答案。

回答by Olivier

I've stumbled across this problem myself, finally I realized that the problem was a naming convention.

我自己偶然发现了这个问题,最后我意识到问题是命名约定。

You cannot name the ViewBag or ViewData poperty containing the SelectList or MultiSelectList to the same name your property model containing the selected items. At least not if you're using the ListBoxFor or DropDownListFor helper.

您不能将包含 SelectList 或 MultiSelectList 的 ViewBag 或 ViewData poperty 命名为与包含所选项目的属性模型相同的名称。至少在您使用 ListBoxFor 或 DropDownListFor 助手时不会。

Here's an example:

下面是一个例子:

    public class Person
    {
          public List<int> Cars { get; set; }
    }

    [HttpGet]
    public ActionResult Create()
    {
          //wont work
          ViewBag.Cars = new SelectList(carsList, "CarId", "Name"); 

          //will work due to different name than the property.
          ViewBag.CarsList = new SelectList(carsList, "CarId", "Name"); 

          return View();
    }

    //View
    @Html.ListBoxFor(model => model.Cars, ViewBag.CarsList as SelectList)

I'm sure theres plenty of other ways doing this, but it solved my problem, hope it will help someone!

我相信还有很多其他方法可以做到这一点,但它解决了我的问题,希望它能帮助别人!

回答by cineam mispelt

The correct answer is that it doesn't work very well. As such I read the MVC code. What you need to do is implement IConvertible and also create a TypeConverter.

正确答案是它不能很好地工作。因此,我阅读了 MVC 代码。您需要做的是实现 IConvertible 并创建一个 TypeConverter。

So, in my instance I had a Countryclass, such that people could choose from a list of countries. No joy in selecting it. I was expecting an object equals comparison on the selectedItemsagainst the listitemsbut no, that's not how it works. Despite the fact that MultiListItemworks and correctly gets the selected items, the moment it is bound to your model it's all based on checking that the string represnetation of your object instance matches the string "value"(or name if that is missing) in the list of items in the SelectItemList.

所以,在我的例子中,我有一个Country类,这样人们可以从一个国家列表中进行选择。没有选择它的乐趣。我期待的对象等于在比较selectedItems反对listitems,但是没有,这不是它是如何工作的。尽管MultiListItem可以正常工作并正确获取所选项目,但当它绑定到您的模型时,这一切都是基于检查您的对象实例的字符串"value"表示是否与项目列表中的字符串(或名称,如果缺少)匹配的SelectItemList

So, implement IConvertible, return the string value from ToStringwhich would match the value in the SelectItemList. e.g in my case CountryCodewas serialized into the SelectItemValueproperty , so in ToString IConvertibleI returned CountryCode. Now it all selects correctly.

因此,实现IConvertible,返回ToStringSelectItemList. 例如在我的情况下CountryCode被序列化到SelectItemValue属性中,所以在ToString IConvertible我返回CountryCode. 现在它全部正确选择。

I will point out the TypeConverteris used on the way in. This time its the inverse. That Countrycodecomes back in and "EN" needs converting into Countryclass instance. That's where the TypeConvertercame in. It's also about the time I realised how difficult this approach is to use.

我会指出TypeConverter是在进入的路上使用的。这次是相反的。这Countrycode又回来了,“EN”需要转换为Country类实例。这就是TypeConverter进来的地方。这也是我意识到这种方法使用起来有多困难的时候。

p.s so on your Categoryclass you need to implement IConvertible. If its from the entity framework as my company is then you'll need to use the partial class to implement IConvertibleand implement ToStringand decorate it with a TypeConverteryou wrote too.

ps 所以在你的Category班级上你需要实现IConvertible. 如果它来自我公司的实体框架,那么您将需要使用部分类来实现IConvertible和实现ToString并用TypeConverter您编写的一个装饰它。

回答by Joshua Hayes

I have also been stuck with this exact same issue and encountered the same problem with ListBox and ListBoxFor.

我也一直被这个完全相同的问题所困扰,并在 ListBox 和 ListBoxFor 上遇到了同样的问题。

No matter what I do, I cannot get selections to occur on the ListBoxFor. If I change to the ListBox and name it something OTHER than the property name of the data I am binding to, selections occur.

无论我做什么,我都无法在 ListBoxFor 上进行选择。如果我更改为 ListBox 并将其命名为我绑定到的数据的属性名称以外的其他名称,则会发生选择。

But then because I'm not using ListBoxFor and the data is sitting inside a model class (Model.Departments) for example, I don't get model binding on the way back to my controller and hence the property is null.

但是因为我没有使用 ListBoxFor 并且数据位于模型类 (Model.Departments) 中,例如,我没有在返回控制器的途中获得模型绑定,因此该属性为空。

EDITI found a solution posted by someone else here; Challenges with selecting values in ListBoxFor

编辑我在这里找到了其他人发布的解决方案; 在 ListBoxFor 中选择值的挑战

回答by nika1218

Also, you can try to clear ModelState for c.Project.Categories in the controller:

此外,您可以尝试清除控制器中 c.Project.Categories 的 ModelState:

[HttpPost]
public ActionResult Index(ModelType model)
{
    ModelState.Remove("Project.Categories");
    return View("Index", model);
}

And use the next construction:

并使用下一个构造:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name"))%>

Where c.Project.Categories is IEnumerable<int>.

c.Project.Categories 在哪里IEnumerable<int>

Sorry for my english. Good luck!

对不起我的英语不好。祝你好运!

回答by Alex

Html.ListboxFor and Html.Listbox work great when you're NOT binding the list box to its data source. I assume the intended use is this:

当您没有将列表框绑定到其数据源时,Html.ListboxFor 和 Html.Listbox 效果很好。我假设预期用途是这样的:

// Model
public class ListBoxEditModel
{
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Category> SelectedCategories { get; set; }
}    

In the view:

在视图中:

@Html.ListBoxFor(m => m.SelectedCategories,
                 new MultiSelectList(Model.Categories, "Id", "Name"))
// or, equivalently
@Html.ListBox("SelectedCategories" ,
                 new MultiSelectList(Model.Categories, "Id", "Name"))

Note that in this case you don't have to explicitly say which values are selected in the MultiSelectList - the model you're binding to takes precedence, even if you do!

请注意,在这种情况下,您不必明确说明在 MultiSelectList 中选择了哪些值 - 您绑定到的模型优先,即使您这样做了!

回答by Alex White

Although this isn't an answer to your main question, it is worth noting that when MVC generates names it will turn something like Project.Tags into Project_Tags, replacing periods with underscores.

尽管这不是您主要问题的答案,但值得注意的是,当 MVC 生成名称时,它会将 Project.Tags 之类的内容转换为 Project_Tags,用下划线替换句点。

The reason that it does this is because a period in an element ID would look like an element named Project with a class of Tags to CSS. Clearly a bad thing, hence the translation to underscores to keep behaviour predictable.

这样做的原因是因为元素 ID 中的句点看起来像一个名为 Project 的元素,其中包含一个标签类到 CSS。显然是一件坏事,因此翻译为下划线以保持行为可预测。

In your first example,

在你的第一个例子中,

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

the listbox is attempting to bind to Model.Project.Categories for your strongly typed Model which has been provided to the page (using the lambda notation). I'm not sure what the second parameter in the ListBoxFor is doing though.

列表框试图绑定到已提供给页面的强类型模型的 Model.Project.Categories(使用 lambda 表示法)。我不确定 ListBoxFor 中的第二个参数在做什么。

What is the Model that is being passed to the page?

传递给页面的模型是什么?

回答by Alex

Try this

尝试这个

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(
        Model.Categories
        ,"Id"
        ,"Name"
        ,Model.Project.Tags.Select(
        x => new SelectListItem()
            {
            Selected = true,
            Text = x.TEXT,
            Value = x.ID.ToString()
            }).ToList())

       )
)%>