Несколько моделей в представлении
Я хочу иметь 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 ViewModel?
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)
}
Ответы
Ответ 1
Существует множество способов...
-
с вашим BigViewModel
вы делаете:
@model BigViewModel
@using(Html.BeginForm()) {
@Html.EditorFor(o => o.LoginViewModel.Email)
...
}
-
вы можете создать 2 дополнительных представления
Login.cshtml
@model ViewModel.LoginViewModel
@using (Html.BeginForm("Login", "Auth", FormMethod.Post))
{
@Html.TextBoxFor(model => model.Email)
@Html.PasswordFor(model => model.Password)
}
и register.cshtml то же самое
после создания вы должны отобразить их в главном представлении и передать им viewmodel/viewdatap >
так что это может быть так:
@{Html.RenderPartial("login", ViewBag.Login);}
@{Html.RenderPartial("register", ViewBag.Register);}
или
@{Html.RenderPartial("login", Model.LoginViewModel)}
@{Html.RenderPartial("register", Model.RegisterViewModel)}
-
Использование ajax частей вашего веб-сайта становится более независимым
-
iframes
, но, вероятно, это не так.
Ответ 2
Я бы рекомендовал использовать 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
будут тогда элементами управления пользователя, которые находятся либо в текущей папке View, либо в общей папке, и хотели бы что-то вроде этого:
/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: (или/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)
}
И там у вас есть одно действие контроллера, просмотр и просмотр файла для каждого действия с каждым полностью отличным и не зависящим друг от друга для чего-либо.
Ответ 3
Другой способ:
@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"})
}
Примечание, что я вручную изменил атрибуты Name для каждого свойства при создании формы. Это необходимо сделать, иначе он не будет правильно отображаться в параметре метода модели типа, когда значения отправляются соответствующему методу обработки. Я бы предложил использовать отдельные методы для обработки этих форм отдельно, для этого примера я использовал методы Login1 и Login2. Метод Login1 требует наличия параметра типа RegisterViewModel и Login2 требует параметра типа LoginViewModel.
если требуется принудительная ссылка, вы можете использовать:
@Html.ActionLink("Edit", "Edit", new { id=Model.Item1.Id })
в методе контроллера для представления необходимо создать переменную типа Tuple, а затем передать ее в представление.
Пример:
public ActionResult Details()
{
var tuple = new Tuple<LoginViewModel, RegisterViewModel>(new LoginViewModel(),new RegisterViewModel());
return View(tuple);
}
или вы можете заполнить два экземпляра LoginViewModel и RegisterViewModel со значениями, а затем передать их в представление.
Ответ 4
Используйте модель представления, содержащую несколько моделей просмотров:
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)
Ответ 5
Нужно ли сделать еще один вид, который содержит эти 2 вида?
Ответ: Нет
Нет ли другого способа, такого как (без BigViewModel):
Да, вы можете использовать Tuple (приносит магия с несколькими образцами).
Код:
@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)
}
Ответ 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)];
}
}
}
Контроллер:
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
Ответ 7
простой способ сделать это
мы можем сначала вызвать всю модель
@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 ;
тогда легко используйте это как Model
Ответ 8
Я хочу сказать, что мое решение было похоже на ответ, представленный на этой странице stackoverflow: ASP.NET MVC 4, несколько моделей в одном представлении?
Однако в моем случае запрос linq, который они использовали в своем контроллере, не работал у меня.
Это запрос:
var viewModels =
(from e in db.Engineers
select new MyViewModel
{
Engineer = e,
Elements = e.Elements,
})
.ToList();
Следовательно, "по вашему мнению, просто укажите, что вы используете коллекцию моделей просмотра", тоже не работало для меня.
Однако небольшая вариация этого решения действительно сработала для меня. Вот мое решение, если это кому-то поможет.
Вот моя модель представления, в которой я знаю, что у меня будет только одна команда, но у этой команды может быть несколько плат (и у меня есть папка ViewModels в моей папке моделей btw, следовательно, пространство имен):
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.Models.ViewModels.TeamBoards". Тогда мне нужно только для каждого, когда я перебираю команды Team. Вот мое мнение:
@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, поэтому мне потребовалось немного времени, чтобы понять это. Поэтому я надеюсь, что этот пост поможет кому-то понять его проект за более короткий промежуток времени.: -)
Ответ 9
Мой совет - сделать модель с большим обзором:
public BigViewModel
{
public LoginViewModel LoginViewModel{get; set;}
public RegisterViewModel RegisterViewModel {get; set;}
}
В вашем Index.cshtml, если, например, у вас есть 2 партиала:
@addTagHelper *,Microsoft.AspNetCore.Mvc.TagHelpers
@model .BigViewModel
@await Html.PartialAsync("_LoginViewPartial", Model.LoginViewModel)
@await Html.PartialAsync("_RegisterViewPartial ", Model.RegisterViewModel )
и в контроллере:
model=new BigViewModel();
model.LoginViewModel=new LoginViewModel();
model.RegisterViewModel=new RegisterViewModel();
Ответ 10
-
Создайте новый класс в вашей модели и свойствах LoginViewModel
и RegisterViewModel
:
public class UserDefinedModel()
{
property a1 as LoginViewModel
property a2 as RegisterViewModel
}
-
Затем используйте UserDefinedModel
в вашем представлении.
Ответ 11
Вы всегда можете передать второй объект в ViewBag или View Data.
Ответ 12
Это упрощенный пример с IEnumerable.
Я использовал две модели в представлении: форму с критериями поиска (модель SearchParams) и сетку для результатов, и я боролся с тем, как добавить модель IEnumerable и другую модель в то же представление. Вот то, что я придумал, надеюсь, это поможет кому-то:
@using DelegatePortal.ViewModels;
@model SearchViewModel
@using (Html.BeginForm("Search", "Delegate", FormMethod.Post))
{
Employee First Name
@Html.EditorFor(model => model.SearchParams.FirstName,
new { htmlAttributes = new { @class = "form-control form-control-sm " } })
<input type="submit" id="getResults" value="SEARCH" class="btn btn-primary btn-lg btn-block" />
}
<br />
@(Html
.Grid(Model.Delegates)
.Build(columns =>
{
columns.Add(model => model.Id).Titled("Id").Css("collapse");
columns.Add(model => model.LastName).Titled("Last Name");
columns.Add(model => model.FirstName).Titled("First Name");
})
...)
SearchViewModel.cs:
namespace DelegatePortal.ViewModels
{
public class SearchViewModel
{
public IEnumerable<DelegatePortal.Models.DelegateView> Delegates { get; set; }
public SearchParamsViewModel SearchParams { get; set; }
....
DelegateController.cs:
// GET: /Delegate/Search
public ActionResult Search(String firstName)
{
SearchViewModel model = new SearchViewModel();
model.Delegates = db.Set<DelegateView>();
return View(model);
}
// POST: /Delegate/Search
[HttpPost]
public ActionResult Search(SearchParamsViewModel searchParams)
{
String firstName = searchParams.FirstName;
SearchViewModel model = new SearchViewModel();
if (firstName != null)
model.Delegates = db.Set<DelegateView>().Where(x => x.FirstName == firstName);
return View(model);
}
SearchParamsViewModel.cs:
namespace DelegatePortal.ViewModels
{
public class SearchParamsViewModel
{
public string FirstName { get; set; }
}
}