简体   繁体   English

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

[英]Multiple Models in a Single View (C# MVC3)

I'm using C# and MVC3. 我正在使用C#和MVC3。

I have a page, for example a Student list, that displays the list of students, which is database driven. 我有一个页面,例如学生列表,显示学生列表,这是由数据库驱动的。 At the same time my menu is database driven, so I also have to send it to the view. 同时我的菜单是数据库驱动的,所以我也必须将它发送到视图。

How can I send both models to a single view? 如何将两个模型发送到单个视图?

You should always create separate ViewModels for your views. 您应始终为视图创建单独的ViewModel。 There should be an abstraction from your Views to your Domain Models. 您的视图应该从您的域模型中抽象出来。 In the demos/tutorials they show it all pretty and easy by simply strongly typing the Views to Domain Models but that's not a good strategy. 在演示/教程中,他们通过简单地强烈键入视图到域模型来显示它非常简单,但这不是一个好策略。 The views should not be dependent on the business objects. 视图不应该依赖于业务对象。

You should implement David Glenn's proposed solution for your current scenario and also for all other views even if requires mapping the domain model to to another view model class. 即使需要将域模型映射到另一个视图模型类,您也应该为当前场景以及所有其他视图实现David Glenn提出的解决方案。

EDIT: 编辑:

If you have lets say a top Menu > TopMenu.aspx And you have multiple partial views inside it > StudentMenu.ascx , ResultMenu.ascx 如果你已经可以说顶部菜单> TopMenu.aspx而你在它里面>多个部分观点StudentMenu.ascxResultMenu.ascx

You will create a View Model for Top Menu > TopMenuViewModel.cs And you will also create view models for partial views > StudentMenuViewModel , ResultMenuViewModel etc. 您将创建顶级菜单>视图模型TopMenuViewModel.cs ,你也将创建局部视图>视图模型StudentMenuViewModelResultMenuViewModel等。

and your TopMenuViewModel will have both > 并且您的TopMenuViewModel将具有两个>

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

and in TopMenu.aspx when rendering the partial you will pass the relevant view model > TopMenu.aspx渲染局部时,您将传递相关的视图模型>

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

Hope it makes sense 希望它有意义

You can create a ViewModel which is a representation of your view and not your business model 您可以创建一个ViewModel,它代表您的视图,而不是您的业务模型

public class StudentPage {

  public IEnumerable<Student> Students { get; set; }

  public Menu Menu { get; set; }

}

Your controller then returns the ViewModel to your view 然后,您的控制器将ViewModel返回到您的视图

public ViewResult Students() {

   var menu = GetMenu();
   var students = Repository.Students();

   var model = new StudentPage {
     Menu = menu,
     Students = students
   }

   return View(model);

}

I'm assuming the menu is a reoccurring feature on your pages so you probably want to break it down a bit like 我假设菜单是你网页上的一个重复出现的功能,所以你可能想要分解它

public class BasePage {

  public Menu Menu { get; set; }

}

public class StudentPage : BasePage {

  public IEnumerable<Student> Students { get; set; }

}

and you could also create a base controller that has the GetMenu() functionality to re-use across multiple controllers. 您还可以创建一个具有GetMenu()功能的基本控制器,以便在多个控制器之间重用。

Note : Classes below should be used in .net 3.5 and lower, because .net 4 introduced as similar class called Tuple and should be used instead. 注意 :下面的类应该在.net 3.5及更低版本中使用,因为.net 4作为类似的类引入,称为Tuple ,应该使用它。

MultiObject<O1, O2, ..> and MultiList<L1, L2, ...> MultiObject<O1, O2, ..>MultiList<L1, L2, ...>

This is how I write such controller actions and views: 这是我编写这样的控制器动作和视图的方式:

public ActionResult MultiModel()
{
    MultiList<User, Company> result = MultiList.New(
        this.repository.GetUsers(),
        this.repository.GetCompanies()
    );
    return View(result);
}

And my view is of type: 我的观点是:

ViewPage<MultiList<User, Company>>

I'm using this reusable convenience class: 我正在使用这个可重用的便利类:

#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

Any when I have to pass multiple lists 任何当我必须传递多个列表时

#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

Data for every view 每个视图的数据

But in your case where you want to pass a menu it's the best to have a base page class that all your pages inherit from and that page class provides all common properties (menu data being one). 但是在您要传递菜单的情况下,最好有一个基页类,所有页面都继承自该页面类,并且该页面类提供所有常用属性(菜单数据为一个)。

To handle multiple model in a single view, I personally use ViewBag. 要在单个视图中处理多个模型,我个人使用ViewBag。

Please note that if you use ViewBag, all the help you get from the compiler is disabled and runtime errors/bugs will occur more likely than if the property has been on a "normal" object and typos would be catched by the compiler. 请注意,如果您使用ViewBag,则会禁用从编译器获得的所有帮助,并且运行时错误/错误的发生可能性超过该属性位于“普通”对象上并且编译器会捕获错别字的情况。

That is the disadvantage of using dynamic objects, however, there are many other advantages. 这是使用动态对象的缺点,但是,还有许多其他优点。 In your controller, you just need to pass the data/model into the ViewBag: 在您的控制器中,您只需将数据/模型传递到ViewBag:

public ActionResult Index() {
            ViewBag.TopMenu = TopMenu();
            ViewBag.Student = Student();
            return View();
        }

Then in the view, call them out: 然后在视图中,将其调出:

@{
    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>

There is another option for this, that gets slated by some MVC purists, but I find that it works well for me. 还有另一种选择,由一些MVC纯粹主义者提出,但我发现它对我有用。 Instead of including the two models on every page where you have a 'menu', (which I am assuming is nearly all the pages), you can display your menu like so, from within your student view: 而不是在每个有“菜单”的页面上包含两个模型(我假设几乎都是所有页面),您可以在学生视图中显示您的菜单:

@Html.RenderAction("Menu");

Which will call to it's own action, generating the menu viewmodel and 'Menu' partial view. 这将调用它自己的动作,生成菜单视图模型和“菜单”局部视图。

To me, this makes sense, but I know a lot of folk don't like it. 对我来说,这是有道理的,但我知道很多人不喜欢它。

In the .Net Framework 4.0 you can use dynamic models. 在.Net Framework 4.0中,您可以使用动态模型。

Roughly: 大致:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        dynamic viewmodel = new ExpandoObject();
        viewmodel.Students = MyStudent();
        viewmodel.MenuItems = MyMenuItems();
        return View(mymodel);
    }
}

How to access in view code: 如何访问视图代码:

@model dynamic

@foreach (Student student in Model.Students)
    }
        <h1>@student.Name</h1>
    }
@foreach (MenuItem menuItem in Model.MenuItems)
    {
        <h1>@menuItem.menuname</h1>
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM