MVC - 将所有ListBox项目传递回Controller

时间:2015-04-05 22:20:32

标签: c# asp.net-mvc model-view-controller listbox

我使用模型第一种方法创建了一个包含Entity Framework的数据库。除此之外,我有ContentEntry类型和Tag类型。每个ContentEntry可以包含多个Tag,每个Tag可以由多个ContentEntry使用。它应该是这样的,在db中没有标记存在两次,因为这是n:m关系: Image of the realtion between Tag and ContentEntry

现在,我尝试创建一个控制器/视图,以创建一个带有ContentEntry的新Tag。我不知道如何创建一个ListBox,将所有他的项目返回给控制器。 JavaScript(使用jQuery)对我来说没问题:

<span class="label">Tags</span>
@Html.ListBoxFor(model => model.Tags, 
                 new MultiSelectList(Model.Tags),
                 new { id = "lbTags" })

<input type="text" id="tbTag" />
<input type="button" value="add" onclick="addTag();" />
<input type="button" value="delete" onclick="delTags();" />

<script>
    function addTag() {
        $('#lbTags').append($('<option>',
            { value: $("#tbTag").val(), text: $("#tbTag").val() }));
    }
    function delTags() {
        $("#lbTags option:selected").remove();
    }
</script>
@Html.ValidationMessageFor(model => model.Tags, "", new { @class = "input-error" })

但我的Tags集合始终为空:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateBlogEntry
  ([Bind(Include = "Id,Published,Title,AccountId,HtmlContent,Tags")]BlogEntry blogEntry)
{
    //blogEntry.Tags is always empty
    if (ModelState.IsValid
    {
        db.ContentEntrySet.Add(blogEntry);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

BlogEntryContentEntry的推导,ContentEntry.TagsICollection<Tag>

有谁知道如何解决这个问题?

修改: 这是我对CreateBlogEntry的GET方法:

public ActionResult CreateBlogEntry()
{
    //ViewBag.Tags = db.TagSet;
    return View(new BlogEntry()
    {
        Published = DateTime.Now,
    });
}

1 个答案:

答案 0 :(得分:3)

默认模型绑定器会将多选中的选定值绑定到集合。

将您的观点更改为

 @Html.ListBox("SelectedTags"
 , new MultiSelectList(Model.Tags,"Name","Name")
 , new { id = "lbTags" })

这种方式即使您从服务器加载值也可以。请注意,我没有使用ListBoxFor,因为我想设置集合的名称。

进入BlogEntry方法的CreateBlogEntry模型将具有如下所示的属性

public IEnumerable<string> SelectedTags{ get; set; }

然后,您可以使用此SelectedTags属性并创建一个进入数据库的新模型。

如果您不想要此行为,则必须覆盖默认模型活页夹的行为。您可以找到关于绑定器in this MSDN post的所有信息。我将尝试使用模型绑定器更新答案,但这足以在同一时间解锁您。

另外请注意,您使用的所有属性BlogEntry都不需要绑定。你可以删除它。

更新 - 自定义模型绑定器版本

您可以创建自己的活页夹,如下所示:

public class FancyBinder:DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext
   ,ModelBindingContext bindingContext
   ,Type modelType)
    {
        if (modelType.Name == "BlogEntry")
        {
            return BindBlogEntry(controllerContext, bindingContext, modelType);
        }
        return base.CreateModel(controllerContext, bindingContext, modelType);
    }

    private static object BindBlogEntry(ControllerContext controllerContext
   ,ModelBindingContext bindingContext
   ,Type modelType)
    {
        var tagsOnForm = controllerContext.HttpContext.Request.Form["Tags"];
        return new BlogEntry
        {
            Content = controllerContext.HttpContext.Request.Form["Content"],
            Tags = GetTags(tagsOnForm)
        };
    }

    private static List<Tag> GetTags(string tagsOnForm)
    {
        var tags = new List<Tag>();
        if (tagsOnForm == null)
            return tags;

        tagsOnForm.Split(',').ForEach(t=>tags.Add(new Tag {Name = t}));
        return tags;
    }
}

您可以在global.asax中连接此绑定器,如下所示:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ModelBinders.Binders.DefaultBinder = new FancyBinder();
    }
}

我希望这很清楚。如果您有疑问,请告诉我。