asp.net-mvc 一个视图中的多个模型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4764011/
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:46:54  来源:igfitidea点击:

Multiple models in a view

asp.net-mvcasp.net-mvc-3

提问by Shawn Mclean

I want to have 2 models in one view. The page contains both LoginViewModeland RegisterViewModel.

我想在一个视图中有 2 个模型。该页面同时包含LoginViewModelRegisterViewModel

e.g.

例如

public class LoginViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
}

public class RegisterViewModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

Do I need to make another ViewModel which holds these 2 ViewModels?

我是否需要制作另一个包含这两个 ViewModel 的 ViewModel?

public BigViewModel
{
    public LoginViewModel LoginViewModel{get; set;}
    public RegisterViewModel RegisterViewModel {get; set;}
}

I need the validation attributes to be brought forward to the view. This is why I need the ViewModels.

我需要将验证属性带到视图中。这就是我需要 ViewModels 的原因。

Isn't there another way such as (without the BigViewModel):

难道没有另一种方式,例如(没有BigViewModel):

 @model ViewModel.RegisterViewModel
 @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
 {
        @Html.TextBoxFor(model => model.Name)
        @Html.TextBoxFor(model => model.Email)
        @Html.PasswordFor(model => model.Password)
 }

 @model ViewModel.LoginViewModel
 @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
 {
        @Html.TextBoxFor(model => model.Email)
        @Html.PasswordFor(model => model.Password)
 }

采纳答案by Omu

There are lots of ways...

有很多方法...

  1. with your BigViewModel you do:

    @model BigViewModel    
    @using(Html.BeginForm()) {
        @Html.EditorFor(o => o.LoginViewModel.Email)
        ...
    }
    
  2. you can create 2 additional views

    Login.cshtml

    @model ViewModel.LoginViewModel
    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
    {
        @Html.TextBoxFor(model => model.Email)
        @Html.PasswordFor(model => model.Password)
    }
    

    and register.cshtml same thing

    after creation you have to render them in the main view and pass them the viewmodel/viewdata

    so it could be like this:

    @{Html.RenderPartial("login", ViewBag.Login);}
    @{Html.RenderPartial("register", ViewBag.Register);}
    

    or

    @{Html.RenderPartial("login", Model.LoginViewModel)}
    @{Html.RenderPartial("register", Model.RegisterViewModel)}
    
  3. using ajax parts of your web-site become more independent

  4. iframes, but probably this is not the case

  1. 使用您的 BigViewModel,您可以:

    @model BigViewModel    
    @using(Html.BeginForm()) {
        @Html.EditorFor(o => o.LoginViewModel.Email)
        ...
    }
    
  2. 您可以创建 2 个额外的视图

    登录.cshtml

    @model ViewModel.LoginViewModel
    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
    {
        @Html.TextBoxFor(model => model.Email)
        @Html.PasswordFor(model => model.Password)
    }
    

    和 register.cshtml同样的事情

    创建后,您必须在主视图中呈现它们并将它们传递给 viewmodel/viewdata

    所以它可能是这样的:

    @{Html.RenderPartial("login", ViewBag.Login);}
    @{Html.RenderPartial("register", ViewBag.Register);}
    

    或者

    @{Html.RenderPartial("login", Model.LoginViewModel)}
    @{Html.RenderPartial("register", Model.RegisterViewModel)}
    
  3. 使用网站的 ajax 部分变得更加独立

  4. iframes,但可能情况并非如此

回答by TheRightChoyce

I'd recommend using Html.RenderActionand PartialViewResults to accomplish this; it will allow you to display the same data, but each partial view would still have a single view model and removes the need for a BigViewModel

我建议使用Html.RenderActionPartialViewResults 来完成此操作;它将允许您显示相同的数据,但每个部分视图仍将具有单个视图模型,并且不需要BigViewModel

So your view contain something like the following:

因此,您的视图包含如下内容:

@Html.RenderAction("Login")
@Html.RenderAction("Register")

Where Login& Registerare both actions in your controller defined like the following:

其中Login&Register是控制器中定义的两个操作,如下所示:

public PartialViewResult Login( )
{
    return PartialView( "Login", new LoginViewModel() );
}

public PartialViewResult Register( )
{
    return PartialView( "Register", new RegisterViewModel() );
}

The Login& Registerwould then be user controls residing in either the current View folder, or in the Shared folder and would like something like this:

然后Login&Register将是驻留在当前视图文件夹或共享文件夹中的用户控件,并且会像这样:

/Views/Shared/Login.cshtml: (or /Views/MyView/Login.cshtml)

/Views/Shared/Login.cshtml:(或 /Views/MyView/Login.cshtml)

@model LoginViewModel
@using (Html.BeginForm("Login", "Auth", FormMethod.Post))
{
    @Html.TextBoxFor(model => model.Email)
    @Html.PasswordFor(model => model.Password)
}

/Views/Shared/Register.cshtml: (or /Views/MyView/Register.cshtml)

/Views/Shared/Register.cshtml:(或 /Views/MyView/Register.cshtml)

@model ViewModel.RegisterViewModel
@using (Html.BeginForm("Login", "Auth", FormMethod.Post))
{
    @Html.TextBoxFor(model => model.Name)
    @Html.TextBoxFor(model => model.Email)
    @Html.PasswordFor(model => model.Password)
}

And there you have a single controller action, view and view file for each action with each totally distinct and not reliant upon one another for anything.

在那里你有一个单独的控制器动作,每个动作的视图和视图文件,每个动作完全不同,并且不依赖于其他任何东西。

回答by Hamid Tavakoli

Another way is to use:

另一种方法是使用:

@model Tuple<LoginViewModel,RegisterViewModel>

I have explained how to use this method both in the view and controller for another example: Two models in one view in ASP MVC 3

我已经解释了如何在视图和控制器中使用此方法作为另一个示例:ASP MVC 3 中一个视图中的两个模型

In your case you could implement it using the following code:

在您的情况下,您可以使用以下代码实现它:

In the view:

在视图中:

@using YourProjectNamespace.Models;
@model Tuple<LoginViewModel,RegisterViewModel>

@using (Html.BeginForm("Login1", "Auth", FormMethod.Post))
{
        @Html.TextBoxFor(tuple => tuple.Item2.Name, new {@Name="Name"})
        @Html.TextBoxFor(tuple => tuple.Item2.Email, new {@Name="Email"})
        @Html.PasswordFor(tuple => tuple.Item2.Password, new {@Name="Password"})
}

@using (Html.BeginForm("Login2", "Auth", FormMethod.Post))
{
        @Html.TextBoxFor(tuple => tuple.Item1.Email, new {@Name="Email"})
        @Html.PasswordFor(tuple => tuple.Item1.Password, new {@Name="Password"})
}

Notethat I have manually changed the Name attributes for each property when building the form. This needs to be done, otherwise it wouldn't get properly mapped to the method's parameter of type model when values are sent to the associated method for processing. I would suggest using separate methods to process these forms separately, for this example I used Login1 and Login2 methods. Login1 method requires to have a parameter of type RegisterViewModel and Login2 requires a parameter of type LoginViewModel.

请注意,我在构建表单时手动更改了每个属性的 Name 属性。这需要完成,否则当值被发送到关联方法进行处理时,它不会正确映射到模型类型的方法参数。我建议使用单独的方法来分别处理这些表单,在这个例子中我使用了 Login1 和 Login2 方法。Login1 方法需要有一个类型为 RegisterViewModel 的参数,而 Login2 需要一个类型为 LoginViewModel 的参数。

if an actionlink is required you can use:

如果需要操作链接,您可以使用:

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

in the controller's method for the view, a variable of type Tuple needs to be created and then passed to the view.

在控制器的视图方法中,需要创建一个 Tuple 类型的变量,然后传递给视图。

Example:

例子:

public ActionResult Details()
{
    var tuple = new Tuple<LoginViewModel, RegisterViewModel>(new LoginViewModel(),new RegisterViewModel());
    return View(tuple);
}

or you can fill the two instances of LoginViewModel and RegisterViewModel with values and then pass it to the view.

或者您可以用值填充 LoginViewModel 和 RegisterViewModel 的两个实例,然后将其传递给视图。

回答by Yini

Use a view model that contains multiple view models:

使用包含多个视图模型的视图模型:

   namespace MyProject.Web.ViewModels
   {
      public class UserViewModel
      {
          public UserDto User { get; set; }
          public ProductDto Product { get; set; }
          public AddressDto Address { get; set; }
      }
   }

In your view:

在您看来:

  @model MyProject.Web.ViewModels.UserViewModel

  @Html.LabelFor(model => model.User.UserName)
  @Html.LabelFor(model => model.Product.ProductName)
  @Html.LabelFor(model => model.Address.StreetName)

回答by VCody

Do I need to make another view which holds these 2 views?

我是否需要制作另一个包含这两个视图的视图?

Answer:No

答:否

Isn't there another way such as (without the BigViewModel):

是不是有另一种方式,例如(没有 BigViewModel):

Yes, you can use Tuple (brings magic in view having multiple model).

是的,您可以使用元组(在具有多个模型的情况下带来魔力)。

Code:

代码:

 @model Tuple<LoginViewModel, RegisterViewModel>


    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
    {
     @Html.TextBoxFor(tuple=> tuple.Item.Name)
     @Html.TextBoxFor(tuple=> tuple.Item.Email)
     @Html.PasswordFor(tuple=> tuple.Item.Password)
    }


    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
     {
      @Html.TextBoxFor(tuple=> tuple.Item1.Email)
      @Html.PasswordFor(tuple=> tuple.Item1.Password)
     }

回答by Morten Frederiksen

Add this ModelCollection.cs to your Models

将此 ModelCollection.cs 添加到您的模型

using System;
using System.Collections.Generic;

namespace ModelContainer
{
  public class ModelCollection
  {
   private Dictionary<Type, object> models = new Dictionary<Type, object>();

   public void AddModel<T>(T t)
   {
      models.Add(t.GetType(), t);
   }

   public T GetModel<T>()
   {
     return (T)models[typeof(T)];
   }
 }
}

Controller:

控制器:

public class SampleController : Controller
{
  public ActionResult Index()
  {
    var model1 = new Model1();
    var model2 = new Model2();
    var model3 = new Model3();

    // Do something

    var modelCollection = new ModelCollection();
    modelCollection.AddModel(model1);
    modelCollection.AddModel(model2);
    modelCollection.AddModel(model3);
    return View(modelCollection);
  }
}

The View:

风景:

enter code here
@using Models
@model ModelCollection

@{
  ViewBag.Title = "Model1: " + ((Model.GetModel<Model1>()).Name);
}

<h2>Model2: @((Model.GetModel<Model2>()).Number</h2>

@((Model.GetModel<Model3>()).SomeProperty

回答by Pnsadeghy

a simple way to do that

一个简单的方法来做到这一点

we can call all model first

我们可以先调用所有模型

@using project.Models

then send your model with viewbag

然后用viewbag发送你的模型

// for list
ViewBag.Name = db.YourModel.ToList();

// for one
ViewBag.Name = db.YourModel.Find(id);

and in view

并且鉴于

// for list
List<YourModel> Name = (List<YourModel>)ViewBag.Name ;

//for one
YourModel Name = (YourModel)ViewBag.Name ;

then easily use this like Model

然后像模型一样轻松地使用它

回答by alin

My advice is to make a big view model:

我的建议是制作一个大视图模型:

public BigViewModel
{
    public LoginViewModel LoginViewModel{get; set;}
    public RegisterViewModel RegisterViewModel {get; set;}
}

In your Index.cshtml, if for example you have 2 partials:

在您的 Index.cshtml 中,例如,如果您有 2 个部分:

@addTagHelper *,Microsoft.AspNetCore.Mvc.TagHelpers
@model .BigViewModel

@await Html.PartialAsync("_LoginViewPartial", Model.LoginViewModel)

@await Html.PartialAsync("_RegisterViewPartial ", Model.RegisterViewModel )

and in controller:

并在控制器中:

model=new BigViewModel();
model.LoginViewModel=new LoginViewModel();
model.RegisterViewModel=new RegisterViewModel(); 

回答by Notso

I want to say that my solution was like the answer provided on this stackoverflow page: ASP.NET MVC 4, multiple models in one view?

我想说我的解决方案就像这个 stackoverflow 页面上提供的答案: ASP.NET MVC 4, multiple models in a view?

However, in my case, the linq query they used in their Controller did not work for me.

但是,就我而言,他们在 Controller 中使用的 linq 查询对我不起作用。

This is said query:

这是说的查询:

var viewModels = 
        (from e in db.Engineers
         select new MyViewModel
         {
             Engineer = e,
             Elements = e.Elements,
         })
        .ToList();

Consequently, "in your view just specify that you're using a collection of view models" did not work for me either.

因此,“在您的视图中仅指定您正在使用一组视图模型”对我来说也不起作用。

However, a slight variation on that solution did work for me. Here is my solution in case this helps anyone.

但是,该解决方案的细微变化确实对我有用。这是我的解决方案,以防万一这对任何人都有帮助。

Here is my view model in which I know I will have just one team but that team may have multiple boards (and I have a ViewModels folder within my Models folder btw, hence the namespace):

这是我的视图模型,我知道我只有一个团队,但该团队可能有多个板(顺便说一句,我的模型文件夹中有一个 ViewModels 文件夹,因此命名空间):

namespace TaskBoard.Models.ViewModels
{
    public class TeamBoards
    {
        public Team Team { get; set; }
        public List<Board> Boards { get; set; }
    }
}

Now this is my controller. This is the most significant difference from the solution in the link referenced above. I build out the ViewModel to send to the view differently.

现在这是我的控制器。这是与上面引用的链接中的解决方案最显着的区别。我构建了 ViewModel 以不同的方式发送到视图。

public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            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();

            if (teamBoards == null)
            {
                return HttpNotFound();
            }
            return View(teamBoards);
        }

Then in my view I do not specify it as a list. I just do "@model TaskBoard.Models.ViewModels.TeamBoards" Then I only need a for each when I iterate over the Team's boards. Here is my view:

然后在我看来,我没有将其指定为列表。我只是做“@model TaskBoard.Models.ViewModels.TeamBoards”然后当我迭代团队的董事会时我只需要一个。这是我的观点:

@model TaskBoard.Models.ViewModels.TeamBoards

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>

<div>
    <h4>Team</h4>
    <hr />


    @Html.ActionLink("Create New Board", "Create", "Board", new { TeamId = @Model.Team.TeamId}, null)
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => Model.Team.Name)
        </dt>

        <dd>
            @Html.DisplayFor(model => Model.Team.Name)
            <ul>
                @foreach(var board in Model.Boards)
                { 
                    <li>@Html.DisplayFor(model => board.BoardName)</li>
                }
            </ul>
        </dd>

    </dl>
</div>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.Team.TeamId }) |
    @Html.ActionLink("Back to List", "Index")
</p>

I am fairly new to ASP.NET MVC so it took me a little while to figure this out. So, I hope this post helps someone figure it out for their project in a shorter timeframe. :-)

我对 ASP.NET MVC 相当陌生,所以我花了一点时间才弄明白。所以,我希望这篇文章可以帮助人们在更短的时间内为他们的项目找到答案。:-)

回答by Nada N. Hantouli

you can always pass the second object in a ViewBag or View Data.

您始终可以在 ViewBag 或 View Data 中传递第二个对象。