web-dev-qa-db-fra.com

Plusieurs modèles dans une seule vue (C # MVC3)

J'utilise C # et MVC3.

J'ai une page, par exemple une liste d'étudiants, qui affiche la liste des étudiants, qui est pilotée par une base de données. En même temps, mon menu est basé sur une base de données, je dois donc également l'envoyer à la vue.

Comment puis-je envoyer les deux modèles à une seule vue?

14
czetsuya

Vous devez toujours créer des modèles ViewModels distincts pour vos vues. Il devrait y avoir une abstraction de vos vues vers vos modèles de domaine. Dans les démonstrations/didacticiels, ils montrent tout cela simplement et simplement en tapant fortement les modèles Vues vers domaine, mais ce n'est pas une bonne stratégie. Les vues ne doivent pas dépendre des objets métier.

Vous devez implémenter la solution proposée par David Glenn pour votre scénario actuel ainsi que pour toutes les autres vues, même si vous devez mapper le modèle de domaine sur une autre classe de modèle de vue.

MODIFIER:

Si vous avez, disons un menu supérieur> TopMenu.aspx Et vous y trouverez plusieurs vues partielles> StudentMenu.ascx, ResultMenu.ascx

Vous allez créer un modèle de vue pour le menu principal> TopMenuViewModel.cs . Vous allez également créer des modèles de vue pour les vues partielles> StudentMenuViewModel, ResultMenuViewModel etc.

et votre TopMenuViewModel aura les deux>

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

et dans TopMenu.aspx lors du rendu du partiel, vous passerez au modèle de vue correspondant>

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

J'espère que c'est logique

14
neebz

Vous pouvez créer un ViewModel qui représente votre vue et non votre modèle d'entreprise.

public class StudentPage {

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

  public Menu Menu { get; set; }

}

Votre contrôleur renvoie ensuite le ViewModel à votre vue

public ViewResult Students() {

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

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

   return View(model);

}

Je suppose que le menu est une fonctionnalité récurrente sur vos pages, vous voulez donc probablement le décomposer un peu comme

public class BasePage {

  public Menu Menu { get; set; }

}

public class StudentPage : BasePage {

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

}

vous pouvez également créer un contrôleur de base doté de la fonctionnalité GetMenu() à réutiliser sur plusieurs contrôleurs.

10
David Glenn

Remarque : Les classes ci-dessous doivent être utilisées dans .net 3.5 et inférieur, car .net 4 est présenté comme une classe similaire appelée Tuple et doit être utilisé à la place.

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

Voici comment j'écris ces actions et ces vues du contrôleur:

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

Et ma vue est de type:

ViewPage<MultiList<User, Company>>

J'utilise cette classe de commodité réutilisable:

#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

Tout quand je dois passer plusieurs listes

#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

Des données pour chaque vue

Mais dans le cas où vous souhaitez passer un menu, il est préférable d’avoir une classe de page de base dont toutes vos pages héritent et cette classe de page fournit toutes les propriétés courantes (les données de menu étant une).

3
Robert Koritnik

Pour gérer plusieurs modèles dans une seule vue, j'utilise personnellement ViewBag. 

Veuillez noter que si vous utilisez ViewBag, toute l'aide que vous obtenez du compilateur est désactivée et les erreurs/bugs d'exécution se produiront plus que si la propriété avait été sur un objet "normal" et les typos seraient interceptés par le compilateur. 

C'est l'inconvénient d'utiliser des objets dynamiques. Cependant, il existe de nombreux autres avantages. Dans votre contrôleur, il vous suffit de transférer les données/modèle dans le ViewBag:

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

Ensuite, dans la vue, appelez-les:

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

Il existe une autre option, proposée par certains puristes de MVC, mais je trouve que cela fonctionne bien pour moi. Au lieu d'inclure les deux modèles sur chaque page pour laquelle vous avez un «menu» (ce qui, je suppose, correspond à presque toutes les pages), vous pouvez afficher votre menu de la manière suivante, dans la vue Étudiant:

@Html.RenderAction("Menu");

Ce qui appelle sa propre action, en générant le modèle de vue de menu et la vue partielle 'Menu'.

Pour moi, cela a du sens, mais je sais que beaucoup de gens ne l'aiment pas.

0
Paddy

Dans .Net Framework 4.0, vous pouvez utiliser des modèles dynamiques. 

Grossièrement:

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

Comment accéder au code de vue: 

@model dynamic

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