Несколько моделей в представлении

Я хочу иметь 2 модели в одном представлении. Страница содержит оба LoginViewModel и RegisterViewModel.

например

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; }
}

мне нужно сделать еще одну ViewModel, которая содержит эти 2 ViewModels?

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

мне нужно, чтобы атрибуты проверки были перенесены в представление, поэтому мне нужны ViewModels.

нет ли другого способа, такого как (без 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)
 }

10 ответов


есть много способов...

  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)
    }
    

    и зарегистрировать.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, но, вероятно, это не так


Я бы посоветовал использовать Html.RenderAction и PartialViewResults для этого; это позволит вам отображать одни и те же данные, но каждое частичное представление все равно будет иметь одну модель представления и устраняет необходимость в BigViewModel

таким образом, ваше представление содержит что-то вроде следующего:

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

здесь Login & Register оба действия в вашем контроллере определены следующим образом:

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

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

на Login & Register тогда будут пользовательские элементы управления находясь либо в текущей папке представления, либо в общей папке и хотел бы что-то вроде этого:

/Вид/Общая/Логин.cshtml: (или /Views / MyView / Login.cshtml) на

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

/Вид/Общая/Регистрация.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)
}

и там у вас есть одно действие контроллера, просмотр и просмотр файла для каждого действия с каждым совершенно отдельным и не зависит друг от друга ни для чего.


другой способ-использовать:

@model Tuple<LoginViewModel,RegisterViewModel>

Я объяснил, как использовать этот метод как в представлении, так и в контроллере для другого примера:две модели в одном представлении в 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"})
}

Примечание что я вручную изменил атрибуты имени для каждого свойства при создании формы. Это нужно сделать, иначе не будет правильно сопоставляться с параметром метода модели типа, когда значения отправляются в связанный метод для обработки. Я бы предложил использовать отдельные методы для обработки этих форм отдельно, для этого примера я использовал методы Login1 и Login2. Метод Login1 требует наличия параметра типа RegisterViewModel, а Login2 - параметра типа LoginViewModel.

если требуется actionlink, вы можете использовать:

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

в методе контроллера для представление, переменная кортежа типа должна быть создана, а затем передана в представление.

пример:

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

или вы можете заполнить два экземпляра LoginViewModel и RegisterViewModel значениями, А затем передать его в представление.


используйте модель представления, содержащую несколько моделей представления:

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

на ваш взгляд:

  @model MyProject.Web.ViewModels.UserViewModel

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

мне нужно сделать другой вид, который содержит эти 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)
     }

добавить этот 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)];
   }
 }
}
:
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);
  }
}

Вид:

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

простой способ сделать это

мы можем вызвать всю модель сперва

@using project.Models

затем отправьте свою модель с viewbag

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

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

и

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

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

затем легко использовать это как модель


Я хочу сказать, что мое решение было похоже на ответ, предоставленный на этой странице stackoverflow:ASP.NET MVC 4, несколько моделей в одном представлении?

однако в моем случае запрос linq, который они использовали в своем контроллере, не работал для меня.

это сказано запрос:

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

следовательно, "на ваш взгляд, просто укажите, что вы используете коллекцию моделей представлений" тоже не сработало для меня.

однако, небольшое изменение на этом решение сработало для меня. Вот мое решение на случай, если это кому-то поможет.

вот моя модель представления, в которой я знаю, что у меня будет только одна команда, но эта команда может иметь несколько плат (и у меня есть папка ViewModels в папке моих моделей кстати, следовательно, пространство имен):

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

теперь это мой контроллер. Это наиболее существенное отличие от решения в приведенной выше ссылке. Я создаю 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);
        }

тогда, на мой взгляд, я не указываю его как список. Я просто делаю " @model TaskBoard.Модели.модель представления.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>

Я довольно новичок в ASP.NET MVC, поэтому мне потребовалось некоторое время, чтобы понять это. Надеюсь, этот пост поможет кому-то понять это для своего проекта в более короткие сроки. :-)


  1. создать новый класс В вашей модели и свойства LoginViewModel и RegisterViewModel:

    public class UserDefinedModel() 
    {
        property a1 as LoginViewModel 
        property a2 as RegisterViewModel 
    }
    
  2. затем использовать UserDefinedModel на ваш взгляд.


вы всегда можете передать второй объект в ViewBag или просмотреть данные.