【问题标题】:Model Binding to a List MVC 4模型绑定到列表 MVC 4
【发布时间】:2013-03-13 02:06:47
【问题描述】:

是否有将 IList 项目绑定到视图的模式。我似乎对 HttpPost 有问题。我知道 Phil Haack 写了一篇不错的文章,但它已经过时了,他说他们可能会对 MVC 4 进行修复。

【问题讨论】:

标签: c# asp.net-mvc-4


【解决方案1】:

如果我需要为每个项目显示一个表单并输入各种属性,我就是这样做的。真的取决于我想要做什么。

ViewModel 看起来像这样:

public class MyViewModel
{
   public List<Person> Persons{get;set;}
}

查看(当然是 BeginForm):

@model MyViewModel


@for( int i = 0; i < Model.Persons.Count(); ++i)
{
    @Html.HiddenFor(m => m.Persons[i].PersonId)
    @Html.EditorFor(m => m.Persons[i].FirstName) 
    @Html.EditorFor(m => m.Persons[i].LastName)         
}

行动:

[HttpPost]public ViewResult(MyViewModel vm)
{
...

请注意,在回发时,只有具有可用输入的属性才会具有值。即,如果 Person 具有 .SSN 属性,则它在 post 操作中不可用,因为它不是表单中的字段。

请注意,MVC 模型绑定的工作方式,它只会查找连续的 ID。因此,在有条件地隐藏一个项目的情况下执行此类操作将导致它在第 5 个项目之后不绑定任何数据,因为一旦遇到 ID 中的间隙,它将停止绑定。即使有 10 个人,您也只能在回发中获得前 4 个:

@for( int i = 0; i < Model.Persons.Count(); ++i)
{
    if(i != 4)//conditionally hide 5th item, 
    { //but BUG occurs on postback, all items after 5th will not be bound to the the list
      @Html.HiddenFor(m => m.Persons[i].PersonId)
      @Html.EditorFor(m => m.Persons[i].FirstName) 
      @Html.EditorFor(m => m.Persons[i].LastName)           
    }
}

【讨论】:

  • 我使用 mvc 5.1 而不是 ++1 我必须这样做:@{ ++i; },在 @foreach() 块内。
  • @Yustme 也许,如果您有 HTML 标记,您可能需要 @{ } 将该上下文切换回 C# 代码。但无论哪种方式都很好。
  • 声明“i”然后使用 foreach 非常难看,尤其是当我们有 FOR LOOPS 时。除非你真的需要,否则请不要使用特定的 List 实现。
  • 好点,有时我不能使用 EditorFor 并且必须构建 &lt;input&gt; 并且喜欢保持迭代器变量的便利性,因为在整个索引访问中重复索引访问感觉非常不干燥地方。在这个例子中,person 变量没有用处,所以我从 foreach 切换到了 for。
  • 我们可以使用 asp 标签助手吗?
【解决方案2】:

一个干净的解决方案是创建一个通用类来处理列表,因此您无需在每次需要时都创建不同的类。

public class ListModel<T>
{
    public List<T> Items { get; set; }

    public ListModel(List<T> list) {
        Items = list;
    }
}

当您返回视图时,您只需要简单地执行以下操作:

List<customClass> ListOfCustomClass = new List<customClass>();
//Do as needed...
return View(new ListModel<customClass>(ListOfCustomClass));

然后在模型中定义列表:

@model ListModel<customClass>

准备出发:

@foreach(var element in Model.Items) {
  //do as needed...
}

【讨论】:

    【解决方案3】:

    ~控制器

    namespace ListBindingTest.Controllers
    {
        public class HomeController : Controller
        {
            //
            // GET: /Home/
    
            public ActionResult Index()
            {
                List<String> tmp = new List<String>();
                tmp.Add("one");
                tmp.Add("two");
                tmp.Add("Three");
                return View(tmp);
            }
    
            [HttpPost]
            public ActionResult Send(IList<String> input)
            {
                return View(input);
            }    
        }
    }
    

    ~强类型索引视图

    @model IList<String>
    
    @{
        Layout = null;
    }
    
    <!DOCTYPE html>
    
    <html>
    <head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    </head>
    <body>
        <div>
        @using(Html.BeginForm("Send", "Home", "POST"))
        {
            @Html.EditorFor(x => x)
            <br />
            <input type="submit" value="Send" />
        }
        </div>
    </body>
    </html>
    

    ~强类型发送视图

    @model IList<String>
    
    @{
        Layout = null;
    }
    
    <!DOCTYPE html>
    
    <html>
    <head>
    <meta name="viewport" content="width=device-width" />
    <title>Send</title>
    </head>
    <body>
        <div>
        @foreach(var element in @Model)
        {
            @element
            <br />
        }
        </div>
    </body>
    </html>
    

    这就是你所要做的,将他的 MyViewModel 模型更改为 IList。

    【讨论】:

    • 史蒂夫,谢谢你的信息,这很好用。我的问题,也许我没有解释是绑定动态列表。桑德森在这篇文章中指出了这一点blog.stevensanderson.com/2010/01/28/…
    • @JT 我是否在控制器中静态键入列表,或者从数据库或文件中获取它并不重要。列表的来源与模型绑定无关。
    • 我的问题是 HttpPost。当视图中的对象列表发生更改时,这些值不会正确发布。这就是桑德森所说的,我正在使用他的方法。 MVC 团队知道这一点,而 Sanderson 的方法是我见过的最好的方法。我向大家道歉,因为我不清楚。
    猜你喜欢
    • 2013-01-27
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-06
    • 2014-05-29
    相关资源
    最近更新 更多