单视图中的多个模型(C#MVC3)

时间:2011-04-23 10:18:41

标签: c# asp.net-mvc asp.net-mvc-3

我正在使用C#和MVC3。

我有一个页面,例如学生列表,它显示了由数据库驱动的学生列表。同时我的菜单是数据库驱动的,所以我也必须将它发送到视图。

如何将两个模型发送到单个视图?

6 个答案:

答案 0 :(得分:14)

您应始终为视图创建单独的ViewModel。您的视图应该从您的域模型中抽象出来。在演示/教程中,他们通过简单地强烈键入视图到域模型来显示它非常简单,但这不是一个好策略。视图不应该依赖于业务对象。

即使需要将域模型映射到另一个视图模型类,您也应该为当前场景以及所有其他视图实现David Glenn的建议解决方案。

修改

如果你有一个顶级菜单> TopMenu.aspx 你在里面有多个局部视图> StudentMenu.ascxResultMenu.ascx

您将为顶层菜单创建一个视图模型> TopMenuViewModel.cs 您还将为部分视图创建视图模型> StudentMenuViewModelResultMenuViewModel等。

并且您的TopMenuViewModel将同时具有>

class TopMenuViewModel 
{
   //all the stuff required in TopMenu.aspx
   StudentMenuViewModel studentvm;
   ResultMenuViewModel resultvm;
}

并在TopMenu.aspx渲染部分时,您将传递相关的视图模型>

Html.RenderPartial('StudentView', Model.studentvm)

希望它有意义

答案 1 :(得分:10)

您可以创建一个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()功能的基本控制器,以便在多个控制器之间重复使用。

答案 2 :(得分: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's first component.</typeparam>
/// <typeparam name="T2">The type of the multi object's 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's first component value.</param>
    /// <param name="second">Multi object's 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's first component value.</param>
    /// <param name="second">Multi object's second component value.</param>
    /// <param name="third">Multi object's 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's first component.</typeparam>
/// <typeparam name="T2">The type of the multi object's 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&lt;T1, T2&gt;"/> 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&lt;T1, T2, T3&gt;"/> 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

每个视图的数据

但是在您要传递菜单的情况下,最好有一个基页类,所有页面都继承自该页面类,并且该页面类提供所有常用属性(菜单数据为一个)。

答案 3 :(得分:2)

要在单个视图中处理多个模型,我个人使用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>

答案 4 :(得分:0)

还有另一种选择,由一些MVC纯粹主义者提出,但我发现它对我有用。您可以在学生视图中显示菜单,而不是在每个页面上都包含两个模型(我假设几乎所有页面都是这样):

@Html.RenderAction("Menu");

将调用它自己的操作,生成菜单视图模型和“菜单”。部分观点。

对我而言,这是有道理的,但我知道很多人不喜欢它。

答案 5 :(得分:0)

在.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>
    }