视图中的多个模型

Sha*_*ean 293 asp.net-mvc asp.net-mvc-3

我希望在一个视图中有2个模型.该页面包含LoginViewModelRegisterViewModel.

例如

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; }
}
Run Code Online (Sandbox Code Playgroud)

我是否需要创建另一个包含这两个ViewModel的ViewModel?

public BigViewModel
{
    public LoginViewModel LoginViewModel{get; set;}
    public RegisterViewModel RegisterViewModel {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

我需要将验证属性提交给视图,这就是我需要ViewModel的原因.

是不是有另一种方式,如(没有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)
 }
Run Code Online (Sandbox Code Playgroud)

Omu*_*Omu 255

有很多方法......

  1. 使用您的BigViewModel:

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

    Login.cshtml

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

    和register.cshtml 一样的东西

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

    所以它可能是这样的:

    @{Html.RenderPartial("login", ViewBag.Login);}
    @{Html.RenderPartial("register", ViewBag.Register);}
    
    Run Code Online (Sandbox Code Playgroud)

    要么

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

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

  • 如果两个文本框由于使用偏见视图而在表单上具有相同的名称,这是一个问题吗? (2认同)
  • 不,应该使用像firebug(在firefox上)之类的东西点击元素本身,你会看到像id ="LoginViewModel_Email"name ="LoginViewModel.Email"这样的东西,所以实际上它们是独一无二的!视图模型应该是您需要的,只需将每个页面发布到不同的URL,您应该没问题 (2认同)

The*_*yce 124

我建议使用Html.RenderAction和PartialViewResults来实现这一目标; 它将允许您显示相同的数据,但每个局部视图仍然只有一个视图模型,并且不需要aBigViewModel

所以你的视图包含如下内容:

@Html.RenderAction("Login")
@Html.RenderAction("Register")
Run Code Online (Sandbox Code Playgroud)

LoginRegister在类似下面的定义控制器两个动作:

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

public PartialViewResult Register( )
{
    return PartialView( "Register", new RegisterViewModel() );
}
Run Code Online (Sandbox Code Playgroud)

LoginRegister随后将居住在无论是当前查看的文件夹的用户控件,或在共享文件夹,并希望这样的事情:

/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)
}
Run Code Online (Sandbox Code Playgroud)

/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)
}
Run Code Online (Sandbox Code Playgroud)

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

  • 是的,你是对的:它会为每个'RenderAction`带来额外的完整MVC循环.我总是忘记它的期货包的一部分,因为我的项目默认包含该dll.如果额外的mvc周期值得在设计方面进行分离,那么它的优先级和应用要求确实如此.很多时候你可以缓存`RenderAction'结果,所以你唯一的打击是通过控制器工厂进行的轻微额外处理. (5认同)
  • 这在设计方面有很多意义,但就效率而言,是否必须经历mvc循环的3个完整周期?http://stackoverflow.com/questions/719027/renderaction-renderpartial/1525767#1525767 (3认同)

Ham*_*oli 110

另一种方法是使用:

@model Tuple<LoginViewModel,RegisterViewModel>
Run Code Online (Sandbox Code Playgroud)

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

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

在视图中:

@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"})
}
Run Code Online (Sandbox Code Playgroud)

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

如果需要actionlink,您可以使用:

@Html.ActionLink("Edit", "Edit", new { id=Model.Item1.Id })
Run Code Online (Sandbox Code Playgroud)

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

例:

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

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


Yin*_*ini 25

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

   namespace MyProject.Web.ViewModels
   {
      public class UserViewModel
      {
          public UserDto User { get; set; }
          public ProductDto Product { get; set; }
          public AddressDto Address { get; set; }
      }
   }
Run Code Online (Sandbox Code Playgroud)

在你看来:

  @model MyProject.Web.ViewModels.UserViewModel

  @Html.LabelFor(model => model.User.UserName)
  @Html.LabelFor(model => model.Product.ProductName)
  @Html.LabelFor(model => model.Address.StreetName)
Run Code Online (Sandbox Code Playgroud)


小智 10

我是否需要创建另一个包含这2个视图的视图?

答:否

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

是的,你可以使用元组(带有多个模型的魔法).

码:

 @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)
     }
Run Code Online (Sandbox Code Playgroud)


Mor*_*sen 6

将此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)];
   }
 }
}
Run Code Online (Sandbox Code Playgroud)

控制器:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

风景:

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
Run Code Online (Sandbox Code Playgroud)


Pns*_*ghy 5

一种简单的方法

我们可以先打电话给所有模特

@using project.Models
Run Code Online (Sandbox Code Playgroud)

然后使用Viewbag发送模型

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

// for one
ViewBag.Name = db.YourModel.Find(id);
Run Code Online (Sandbox Code Playgroud)

并鉴于

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

//for one
YourModel Name = (YourModel)ViewBag.Name ;
Run Code Online (Sandbox Code Playgroud)

然后像模型一样轻松使用