ASP MVC 3在一个视图中包含两个模型


91

我有2个型号:

public class Person
{
    public int PersonID { get; set; }
    public string PersonName { get; set; }
}
public class Order
{
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

我想在SINGLE视图中编辑两个类的对象,因此需要以下内容:

@model _try2models.Models.Person
@model _try2models.Models.Order

@using(Html.BeginForm())
{
    @Html.EditorFor(x => x.PersonID)
    @Html.EditorFor(x => x.PersonName)
    @Html.EditorFor(x=>x.OrderID)
    @Html.EditorFor(x => x.TotalSum)
}

当然,这是行不通的:.cshtml文件中仅允许一个'model'语句。可能有一些解决方法?


1
我的回答对您有帮助吗?
安德鲁

我使用ViewBag的每个视图对我有用,请选中选项以了解多个选项,为我节省了很少的时间,而不是创建视图模型或局部视图
shaijut 2015年

Answers:


118

创建一个包含两个模型的父视图模型。

public class MainPageModel{
    public Model1 Model1{get; set;}
    public Model2 Model2{get; set;}
}

这样,您可以在以后以最小的工作量添加其他模型。


2
使用此解决方案时,请记住,对Model1或Model2的更改可能会对MainPageModel产生影响。此外,它们主要包含的数据超出视图的实际需求。如果您的MainPage是其他控制器中已经存在的事物的组合,那么从RenderPartial切换到RenderAction将使您保持事物的整洁分离。考虑阅读《德米特耳法则》:en.wikipedia.org/wiki/Law_of_Demeter
Fenton

1
@Andi-我按照上面的建议创建了模型。但是,当我右键单击控制器并尝试创建Crud控制器时,它不起作用吗?有什么建议?如何为上述模型创建具有自动视图的Crud控制器?
NoviceMe,2012年

2
在我看到的解决此问题的所有方法中,这是最适合我的方法。这是迄今为止最简单的解决方案。
Ciaran Gallagher

4
当你问自己“我为什么没想到那件事吗?” 伟大的解决方案
拉斐尔AMS 2014年

1
@Andi我将如何在控制器中公开各个模型的方法?
Volatil3 2014年

53

要使用元组,您需要执行以下操作,在视图中将模型更改为:

@model Tuple<Person,Order>

要使用@html方法,您需要执行以下操作:

@Html.DisplayNameFor(tuple => tuple.Item1.PersonId)

要么

@Html.ActionLink("Edit", "Edit", new { id=Model.Item1.Id }) |

Item1指示传递给Tuple方法的第一个参数,您可以使用Item2访问第二个模型,依此类推。

在您的控制器中,您需要创建一个类型为Tuple的变量,然后将其传递给视图:

    public ActionResult Details(int id = 0)
    {
        Person person = db.Persons.Find(id);
        if (person == null)
        {
            return HttpNotFound();
        }
        var tuple = new Tuple<Person, Order>(person,new Order());

        return View(tuple);
    }

另一个示例:视图中有多个模型


1
千万不要Tuple在这种情况下- OP是想要编辑的数据,并且Tuple没有默认的构造函数,所以当表单提交模式不能绑定

永远不要把话说绝了。这里有点强大。
约翰尼,

47

不需要创建自定义模型的另一个选项是使用Tuple <>

@model Tuple<Person,Order>

按照Andi的回答,它不像创建一个包含两个类的新类那样干净,但是它是可行的。


在MVC 3中,它给出了错误文件中仅允许一个'model'语句。知道如何解决吗?
GibboK 2012年

1
@GibboK-我在MVC3中使用它就好了。确保您没有两@model行?
Bobson,2012年

3
:您可以获取每个型号的性能@Model.Item1.Property@Model.Item2.Property用于PersonOrder分别
user2019515

1
我在视图中使用过Tuple。但是,我无法在控制器中获取模型值。但是,当我按照@Andi的建议使用父视图模型时,我在控制器中得到了模型值。
Naren 2014年

1
@StephenMuecke-嗯。我从没考虑过,但是你是对的。安德鲁的答案的另一个原因是更好的通用性。当您选择轻巧的替代品(像这样)时,您确实放弃了功能。
Bobson,2016年

10

如果您喜欢非常扁平的模型,只是为了支持视图,则应创建特定于此特定视图的模型...

public class EditViewModel
    public int PersonID { get; set; }
    public string PersonName { get; set; }
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

许多人使用AutoMapper将其域对象映射到其平面视图。

视图模型的想法是它仅支持视图-没有别的。每个视图只有一个,以确保它仅包含该视图所需的内容,而不包含其他视图所需的属性负载。


5

好的,每个人都说得通,我把所有的内容都放在这里,以帮助像我这样的新手,这些人需要从头到尾进行解释。

根据@Andrew的答案,您将自己的大班设为2个班。

public class teamBoards{
    public Boards Boards{get; set;}
    public Team Team{get; set;}
}

然后在您的控制器中填充2个模型。有时您只需要填写一个即可。然后在返回中,您引用大型模型,它将其中的2带入View。

            TeamBoards teamBoards = new TeamBoards();


        teamBoards.Boards = (from b in db.Boards
                               where b.TeamId == id
                               select b).ToList();
        teamBoards.Team = (from t in db.Teams
                              where t.TeamId == id
                          select t).FirstOrDefault();

 return View(teamBoards);

在视图顶部

@model yourNamespace.Models.teamBoards

然后加载引用大型模型内容的输入或显示:

 @Html.EditorFor(m => Model.Board.yourField)
 @Html.ValidationMessageFor(m => Model.Board.yourField, "", new { @class = "text-danger-yellow" })

 @Html.EditorFor(m => Model.Team.yourField)
 @Html.ValidationMessageFor(m => Model.Team.yourField, "", new { @class = "text-danger-yellow" })

和。。。.back在牧场上,当邮政进来时,请参考大类:

 public ActionResult ContactNewspaper(teamBoards teamboards)

并利用模型返回的内容:

string yourVariable = teamboards.Team.yourField;

该类中可能包含一些DataAnnotation Validation东西,并且可能将if(ModelState.IsValid)放在保存/编辑块的顶部。。。


4

实际上,有一种方法可以在一个视图上使用两个或多个模型,而无需将它们包装在包含两个模型的类中。

以Employee为例的模型:

@model Employee

其实就是这样。

@{ var Model = ViewBag.model as Employee; }

因此,View(employee)方法将模型设置为ViewBag,然后ViewEngine对其进行投射。

这意味着,

ViewBag.departments = GetListOfDepartments();
    return View(employee);

可以像这样使用

            @model  Employee
        @{
                var DepartmentModel = ViewBag.departments as List<Department>;
        }

本质上,您可以将ViewBag中的任何内容用作“模型”,因为无论如何它都是这样工作的。我并不是说这在架构上是理想的,但是有可能。


3

只需创建一个包含所有必需信息的单一视图模型,通常我要做的就是为每个视图创建一个模型,这样我就可以针对每个视图进行特定设置,或者创建一个父模型并继承它。或制作一个包含两个视图的模型。

我个人只是将它们添加到一个模型中,但这就是我做的方法:

public class xViewModel
{
    public int PersonID { get; set; }
    public string PersonName { get; set; }
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

@model project.Models.Home.xViewModel

@using(Html.BeginForm())
{
    @Html.EditorFor(x => x.PersonID)
    @Html.EditorFor(x => x.PersonName)
    @Html.EditorFor(x => x.OrderID)
    @Html.EditorFor(x => x.TotalSum)
}


0

从未讨论过的另一种方法是在MSSQL中使用您要呈现的所有数据创建视图。然后使用LINQ to SQL或其他将其映射的方法。在控制器中,将其返回到视图。做完了



0

在asp.net中,除了一个视图模型之外,您还可以制作多个局部视图,并为每个视图分配不同的模型视图,例如:

   @{
        Layout = null;
    }

    @model Person;

    <input type="text" asp-for="PersonID" />
    <input type="text" asp-for="PersonName" />

然后是另一个局部视图模型,用于订单模型

    @{
        Layout = null;
     }

    @model Order;

    <input type="text" asp-for="OrderID" />
    <input type="text" asp-for="TotalSum" />

然后在您的主视图中加载两个局部视图

<partial name="PersonPartialView" />
<partial name="OrderPartialView" />

-1

希望对您有所帮助!

我将ViewBag用于项目,将Model用于任务,因此通过这种方式,我在单个视图和控制器中使用两个模型,我定义了viewbag的值或数据

List<tblproject> Plist = new List<tblproject>();
            Plist = ps.getmanagerproject(c, id);

            ViewBag.projectList = Plist.Select(x => new SelectListItem
            {
                Value = x.ProjectId.ToString(),
                Text = x.Title
            });

鉴于tbltask和projectlist是我的两个差异模型

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} @model清单

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.