【问题标题】:Multiple Models in a Single View (C# MVC3)单个视图中的多个模型 (C# MVC3)
【发布时间】:2011-04-23 10:18:40
【问题描述】:

我正在使用 C# 和 MVC3。

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

    编辑:

    如果你有一个顶级菜单 > TopMenu.aspx 而且你里面有多个局部视图 > StudentMenu.ascx, ResultMenu.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)

    希望有意义

    【讨论】:

    • 您好,感谢您的回复。你的意思是这里:asp.net?演示/教程?
    • 是的,但如果你正在构建一个大型项目,你应该总是抽象你的领域对象和视图模型。
    • 您好,感谢您的提示,这是从一开始就分离域模型的计划。但是我对如何从控制器发送模型对象感到困惑,特别是当我将页面分成几个部分视图时。并且某些部分视图取决于某些模型。例如在我的部分视图菜单中,假设我有一个 MenuViewModel。在匹配更大的模型 CompilationViewModel(菜单、学生等)中添加 MenuViewModel,我将如何在给定视图中访问该特定视图模型?或者更糟糕的是在单个视图中访问 2 个视图模型?谢谢。
    • 您好,感谢您的示例代码。这确实很有帮助,我只是想我可以不从主视图传递模型,直接从局部视图访问视图模型。
    • 恐怕我不明白你的意思。无论您是从主页还是控制器呈现对象,都需要将对象传递给您的 PartialView。 (如果您从收到的问题回复中选择一个答案,那么对于遇到相同问题的其他用户也很好)
    【解决方案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() 功能的基本控制器,以便跨多个控制器重复使用。

    【讨论】:

    • 您好,感谢您的回复。我实际上是在做一个具有菜单定义的基类控制器(在 OnActionExecuting 上)。我的问题是我总是必须定义这个吗? var model = new StudentPage { Menu = menu, Students = students } return View(model);问题是,我可能有另一个实体说教师然后我将有教师页面(教师 + 菜单)?顺便说一句,如何区分视图中的 2 个模型?在这里对不起新手。
    • @czetsuya:如果你有one view model per view,它确实是最灵活的。因此,在有教师页面的情况下,是的,您还将有一个 TeacherPage 类作为您的视图模型,您将在该视图的控制器操作中实例化它,并作为您的模型返回。希望对您有所帮助。
    • 我们可以在主页中使用包含一个模型的两个局部视图吗?和上面有什么区别?谢谢
    【解决方案3】:

    注意:以下类应在 .net 3.5 及更低版本中使用,因为 .net 4 引入了类似的名为 Tuple 的类,应改为使用。

    MultiObject&lt;O1, O2, ..&gt;MultiList&lt;L1, L2, ...&gt;

    这就是我编写此类控制器操作和视图的方式:

    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
    

    每个视图的数据

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

    【讨论】:

    • 嗨罗伯特,您的 MultiObject 是否优于 Tuple 以及您的 MultiList 是否优于 Tuple,List...
    • @SurjitSamra:我编写这些类的主要原因是因为我在 .net 3.5 中需要它们。 Tuple 进入 .net 4 所以......但除此之外,MultiObject 没有优势,但 MultiList 有简洁的原因。在 .net 4 中我无论如何都不会使用它们...
    【解决方案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>
            }
        

        【讨论】:

          猜你喜欢
          • 2011-08-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-19
          相关资源
          最近更新 更多