Несколько моделей в одном представлении (С# MVC3)
Я использую С# и MVC3.
У меня есть страница, например, список учеников, который отображает список студентов, которые управляются базой данных. В то же время мое меню управляется базой данных, поэтому мне также нужно отправить его в представление.
Как отправить обе модели на один вид?
Ответы
Ответ 1
Вы всегда должны создавать отдельные ViewModels для своих просмотров. Должна быть абстракция от ваших просмотров до ваших моделей доменов. В демонстрациях/учебных пособиях они показывают все это довольно и просто, просто набрав модели Views to Domain, но это не очень хорошая стратегия. Представления не должны зависеть от бизнес-объектов.
Вы должны реализовать предложенное Дэвидом Гленном решение для вашего текущего сценария, а также для всех других представлений, даже если требуется сопоставить модель домена с другим классом модели представления.
EDIT:
Если вы скажете верхнее Меню > TopMenu.aspx
И внутри него есть несколько частичных представлений > StudentMenu.ascx
, ResultMenu.ascx
Вы создадите View Model для Top Menu > TopMenuViewModel.cs
И вы также создадите модели представления для частичных представлений > StudentMenuViewModel
, ResultMenuViewModel
и т.д.
и ваш TopMenuViewModel будет иметь как >
class TopMenuViewModel
{
//all the stuff required in TopMenu.aspx
StudentMenuViewModel studentvm;
ResultMenuViewModel resultvm;
}
и в TopMenu.aspx
при рендеринге части вы пройдете соответствующую модель представления >
Html.RenderPartial('StudentView', Model.studentvm)
Надеюсь, что это имеет смысл
Ответ 2
Вы можете создать ViewModel, который является представлением вашего представления, а не вашей бизнес-модели.
public class StudentPage {
public IEnumerable<Student> Students { get; set; }
public Menu Menu { get; set; }
}
Затем ваш контроллер возвращает ViewModel в ваш вид
public ViewResult Students() {
var menu = GetMenu();
var students = Repository.Students();
var model = new StudentPage {
Menu = menu,
Students = students
}
return View(model);
}
Я предполагаю, что меню является повторяющейся функцией на ваших страницах, поэтому вы, вероятно, захотите сломать ее немного как
public class BasePage {
public Menu Menu { get; set; }
}
public class StudentPage : BasePage {
public IEnumerable<Student> Students { get; set; }
}
и вы также можете создать базовый контроллер, который имеет функции GetMenu()
для повторного использования через несколько контроллеров.
Ответ 3
Примечание. Классы ниже должны использоваться в .net 3.5 и ниже, потому что .net 4 введен как аналогичный класс с именем Tuple
и должен использоваться вместо него.
MultiObject<O1, O2, ..>
и MultiList<L1, L2, ...>
Вот как я пишу такие действия и представления контроллера:
public ActionResult MultiModel()
{
MultiList<User, Company> result = MultiList.New(
this.repository.GetUsers(),
this.repository.GetCompanies()
);
return View(result);
}
И мое представление имеет тип:
ViewPage<MultiList<User, Company>>
Я использую этот многоразовый класс удобства:
#region MultiObject static helper class
/// <summary>
/// Provides static methods for creating multi objects with type inference.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")]
public static class MultiObject
{
/// <summary>
/// Creates a new <see cref="MultiObject{T1, T2}"/> object instance.
/// </summary>
/// <typeparam name="T1">The type of the first object.</typeparam>
/// <typeparam name="T2">The type of the second object.</typeparam>
/// <param name="first"><typeparamref name="T1"/> object instance.</param>
/// <param name="second"><typeparamref name="T2"/> object instance.</param>
/// <returns>
/// Returns a <see cref="MultiObject{T1, T2}"/> of <typeparamref name="T1"/> and <typeparamref name="T2"/> object instances.
/// </returns>
public static MultiObject<T1, T2> New<T1, T2>(T1 first, T2 second)
{
return new MultiObject<T1, T2>(first, second);
}
/// <summary>
/// Creates a new <see cref="MultiObject{T1, T2, T3}"/> object instance.
/// </summary>
/// <typeparam name="T1">The type of the first object.</typeparam>
/// <typeparam name="T2">The type of the second object.</typeparam>
/// <typeparam name="T3">The type of the third object.</typeparam>
/// <param name="first"><typeparamref name="T1"/> object instance.</param>
/// <param name="second"><typeparamref name="T2"/> object instance.</param>
/// <param name="third"><typeparamref name="T3"/> object instance.</param>
/// <returns>
/// Returns a <see cref="MultiObject{T1, T2, T3}"/> of <typeparamref name="T1"/>, <typeparamref name="T2"/> and <typeparamref name="T3"/> objects instances.
/// </returns>
public static MultiObject<T1, T2, T3> New<T1, T2, T3>(T1 first, T2 second, T3 third)
{
return new MultiObject<T1, T2, T3>(first, second, third);
}
}
#endregion
#region MultiObject<T1, T2>
/// <summary>
/// Represents a 2-multi object, or pair.
/// </summary>
/// <typeparam name="T1">The type of the multi object first component.</typeparam>
/// <typeparam name="T2">The type of the multi object second component.</typeparam>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")]
public class MultiObject<T1, T2>
{
/// <summary>
/// Gets or sets the value of the first multi object component.
/// </summary>
/// <value>The first.</value>
public T1 First { get; set; }
/// <summary>
/// Gets or sets the value of the second multi object component.
/// </summary>
/// <value>The second multi object component value.</value>
public T2 Second { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="MultiObject{T1, T2}"/> class.
/// </summary>
/// <param name="first">Multi object first component value.</param>
/// <param name="second">Multi object second component value.</param>
public MultiObject(T1 first, T2 second)
{
this.First = first;
this.Second = second;
}
}
#endregion
#region MultiObject<T1, T2, T3>
/// <summary>
/// Creates a new 3-multi object, or triple.
/// </summary>
/// <typeparam name="T1">The value of the first component of the multi object.</typeparam>
/// <typeparam name="T2">The value of the second component of the multi object.</typeparam>
/// <typeparam name="T3">The value of the third component of the multi object.</typeparam>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")]
[SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
public class MultiObject<T1, T2, T3> : MultiObject<T1, T2>
{
/// <summary>
/// Gets or sets the value of the third multi object component.
/// </summary>
/// <value>The third multi object component value.</value>
public T3 Third { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="MultiObject{T1, T2, T3}"/> class.
/// </summary>
/// <param name="first">Multi object first component value.</param>
/// <param name="second">Multi object second component value.</param>
/// <param name="third">Multi object third component value.</param>
public MultiObject(T1 first, T2 second, T3 third)
: base(first, second)
{
this.Third = third;
}
}
#endregion
Любой, когда мне нужно передать несколько списков
#region MultiObject static helper class
/// <summary>
/// Provides static methods for creating multi objects with type inference.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")]
public static class MultiList
{
/// <summary>
/// Creates a new <see cref="MultiObject{T1, T2}"/> object instance.
/// </summary>
/// <typeparam name="T1">The type of the first object.</typeparam>
/// <typeparam name="T2">The type of the second object.</typeparam>
/// <param name="first"><typeparamref name="T1"/> object instance.</param>
/// <param name="second"><typeparamref name="T2"/> object instance.</param>
/// <returns>
/// Returns a <see cref="MultiObject{T1, T2}"/> of <typeparamref name="T1"/> and <typeparamref name="T2"/> object instances.
/// </returns>
public static MultiList<T1, T2> New<T1, T2>(IList<T1> first, IList<T2> second)
{
return new MultiList<T1, T2>(first, second);
}
/// <summary>
/// Creates a new <see cref="MultiObject{T1, T2, T3}"/> object instance.
/// </summary>
/// <typeparam name="T1">The type of the first object.</typeparam>
/// <typeparam name="T2">The type of the second object.</typeparam>
/// <typeparam name="T3">The type of the third object.</typeparam>
/// <param name="first"><typeparamref name="T1"/> object instance.</param>
/// <param name="second"><typeparamref name="T2"/> object instance.</param>
/// <param name="third"><typeparamref name="T3"/> object instance.</param>
/// <returns>
/// Returns a <see cref="MultiObject{T1, T2, T3}"/> of <typeparamref name="T1"/>, <typeparamref name="T2"/> and <typeparamref name="T3"/> objects instances.
/// </returns>
public static MultiList<T1, T2, T3> New<T1, T2, T3>(IList<T1> first, IList<T2> second, IList<T3> third)
{
return new MultiList<T1, T2, T3>(first, second, third);
}
}
#endregion
#region MultiList<T1, T2>
/// <summary>
/// Represents a 2-multi object, or pair.
/// </summary>
/// <typeparam name="T1">The type of the multi object first component.</typeparam>
/// <typeparam name="T2">The type of the multi object second component.</typeparam>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")]
public class MultiList<T1, T2> : MultiObject<IList<T1>, IList<T2>>
{
/// <summary>
/// Initializes a new instance of the <see cref="MultiList<T1, T2>"/> class.
/// </summary>
/// <param name="first">The first.</param>
/// <param name="second">The second.</param>
public MultiList(IList<T1> first, IList<T2> second) : base(first, second) { }
}
#endregion
#region MultiList<T1, T2, T3>
/// <summary>
/// Creates a new 3-multi object, or triple.
/// </summary>
/// <typeparam name="T1">The value of the first component of the multi object.</typeparam>
/// <typeparam name="T2">The value of the second component of the multi object.</typeparam>
/// <typeparam name="T3">The value of the third component of the multi object.</typeparam>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")]
[SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
public class MultiList<T1, T2, T3> : MultiObject<IList<T1>, IList<T2>, IList<T3>>
{
/// <summary>
/// Initializes a new instance of the <see cref="MultiList<T1, T2, T3>"/> class.
/// </summary>
/// <param name="first">The first.</param>
/// <param name="second">The second.</param>
/// <param name="third">The third.</param>
public MultiList(IList<T1> first, IList<T2> second, IList<T3> third) : base(first, second, third) { }
}
#endregion
Данные для каждого вида
Но в вашем случае, когда вы хотите передать меню, лучше всего иметь базовый класс страниц, который наследует все ваши страницы, и этот класс страниц предоставляет все общие свойства (данные меню являются одним).
Ответ 4
Чтобы обрабатывать несколько моделей в одном представлении, я лично использую ViewBag.
Обратите внимание, что если вы используете ViewBag, вся помощь, которую вы получаете от компилятора, отключена, а ошибки/ошибки времени выполнения будут происходить с большей вероятностью, чем если бы свойство было на "нормальном" объекте, и опечатки были бы уловлены компилятором,
Это недостаток использования динамических объектов, однако есть много других преимуществ. В вашем контроллере вам просто нужно передать данные/модель в ViewBag:
public ActionResult Index() {
ViewBag.TopMenu = TopMenu();
ViewBag.Student = Student();
return View();
}
Затем в представлении вызовите их:
@{
ViewBag.Title = "Index_ViewBag";
}
<h2>Index View Bag</h2>
<table>
<tr>
@foreach (var menu in ViewBag.TopMenu)
{
<td>
<a href="@menu.URL">@menu.Name</a>
</td>
}
</tr>
</table>
<p>
<ul>
@foreach (var student in ViewBag.Student)
{
<li>
<a href="@student.URL">@student.Name</a>
</li>
}
</ul>
</p>
Ответ 5
Есть еще один вариант для этого, который получает некоторые пуристы MVC, но я считаю, что он работает хорошо для меня. Вместо того, чтобы включать две модели на каждой странице, где у вас есть "меню" (которое я предполагаю, это почти все страницы), вы можете отобразить свое меню, как это, изнутри вашего студенческого вида:
@Html.RenderAction("Menu");
который будет вызывать его собственное действие, генерируя режим просмотра меню и частичный вид "Меню".
Для меня это имеет смысл, но я знаю, что многим людям это не нравится.
Ответ 6
В .Net Framework 4.0 вы можете использовать динамические модели.
Грубо:
public class HomeController : Controller
{
public ActionResult Index()
{
dynamic viewmodel = new ExpandoObject();
viewmodel.Students = MyStudent();
viewmodel.MenuItems = MyMenuItems();
return View(mymodel);
}
}
Как получить доступ к коду вида:
@model dynamic
@foreach (Student student in Model.Students)
}
<h1>@student.Name</h1>
}
@foreach (MenuItem menuItem in Model.MenuItems)
{
<h1>@menuItem.menuname</h1>
}