@ Html.Partial () has an overload in which you can specify data, and not just the name of the view.
If you want to display all the programs and for each indicate all users of these programs, then you need something in the spirit of:
public ActionResult ProgsWithUsers() { IEnumerable<Prog> progs = db.Progs.Include(x => x.Users).ToArray(); return View(progs); }
In the view:
@model IEnumerable<WebApplication3.Models.Prog> <table class="table table-bordered"> <thead> <tr> <th>Номер строки</th> <th>Название программы</th> <th>Пользователи</th> </tr> </thead> <tbody> @foreach (var program in Model) { <tr> <th scope="row">@program.Id</th> <td>@program.Name</td> </tr> @if(program.Users.Count() > 0) { <td>@Html.Partial("Users", program.Users)</td> } else { <td>–</td> } } </tbody> </table>
Well, in the partial view:
@model IEnumerable<WebApplication3.Models.User> @foreach (var user in Model) { <div>@user.Surname</div> }
Update. If you need to make a conclusion first of all programs, and then of all users, then there are options.
The most obvious and simple. Select data in one action:
public ActionResult CompositeProgsAndUsers() { IEnumerable<Prog> progs = db.Progs; IEnumerable<User> users = db.Users; var model = new CompositeProgsAndUsersViewModel { Progs = progs, Users = users, } return View(model); }
The view is based on the CompositeProgsAndUsersViewModel model and contains a call to two partial ones:
@model IEnumerable<CompositeProgsAndUsersViewModel> @Html.Partial("Progs", Model.Progs) @Html.Partial("Users", Model.Users)
What is convenient this option - the fact that the view is obtained thin, point and can be reused.
Partial representations will have as a model IEnumerable and IEnumerable, respectively (write yourself, the principle you already seem to understand)
If you want to display users with programs, see the code above with .Include (x => x.Progs).
You can also drop the model class and just cram everything into the viewbag (you have the code above, I just don’t understand what prevented everything from being put into the ViewBag, and not shoving it either in the ViewBag or in ViewData; perhaps there are some limitations, o which I have already forgotten, because I don’t like to use viewbag / viewdata - but so far this approach seems to me inconsistent , you decide either to go there or here)
Another option is to call the action inside the view via the ChildActionOnly mechanism (in my opinion, it may be less appropriate).
And for asp.net core there is a new way - through inject (see the answer of Pavel Mayorov in this topic ).
Update 2. Your specific ViewModel will look like this:
public class CompositeProgsAndUsersViewModel { public IEnumerable<Prog> Progs { get; set; } public IEnumerable<User> Users { get; set; } }
I am a supporter of writing separate ViewModel , and I do not use domain classes as view models.
As an example, I always cite the RegisterViewModel model from the ASP.NET Identity set (if identity is enabled in your asp.net project, look at the code) when the model has password and password confirmation fields:
public class RegisterViewModel { [Required] [Display(Name = "UserName")] public string UserName { get; set; } [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } }