Reputation: 835
I have 2 models; TypeOne
and Project_Screen
. I need a view that makes 2 tables with information from both of those tables. I tried to use this guide to making a view model which helped but isnt doing quite the same thing I am: https://dotnettutorials.net/lesson/view-model-asp-net-core-mvc/
This is the View Model I made:
public class MyProjectsViewModel
{
public Project_Screen Project_Screen { get; set; }
public TypeOne TypeOne { get; set; }
}
This is the controller:
public class ProfileController : Controller
{
private readonly Natural_ResourcesContext _context;
public ProfileController(Natural_ResourcesContext context)
{
_context = context;
}
// GET: Profile
public ActionResult Index()
{
Project_Screen project_Screen = (Project_Screen)(from s in _context.Project_Screen
where s.DSN_PM == User.Identity.Name
select s);
TypeOne typeOne = (TypeOne)(from x in _context.TypeOne
where x.Name == User.Identity.Name
select x);
MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
{
Project_Screen = project_Screen,
TypeOne = typeOne
};
return View(myProjectsViewModel);
}
}
As you can see, project_Screen
and typeOne
are all records in which Manager = Name
.
Then in the view I'd like to display these something like this:
@model EnvApp.ViewModels.MyProjectsViewModel
@{
ViewData["Title"] = "Projects";
}
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.County)
</td>
<td>
@Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="@item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.County)
</td>
<td>
@Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="@item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
I get the compiler error CS1579 on ````Model```:
foreach statement cannot operate on variables of type 'MyProjectsViewModel' because 'MyProjectsViewModel' does not contain a public instance or extension definition for 'GetEnumorator'
Which I think makes sense, because I have not denoted Project_Screen
or TypeOne
as an object that holds multiple records, but I'm not quite sure how to do this.
Am I on the right track or have I misunderstood this? What am I missing?
EDIT 1:
I did exactly what Md Farid Uddin Kiron said so the code in his answer reflects my view model and view. However I am still having issues with my controller.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using EnvApp.ViewModels;
using EnvApp.Models.DB;
namespace EnvApp.Controllers
{
public class ProfileController : Controller
{
private readonly Natural_ResourcesContext _context;
public ProfileController(Natural_ResourcesContext context)
{
_context = context;
}
// GET: Profile
public ActionResult Index()
{
Project_Screen project_Screen = (Project_Screen)(from s in _context.Project_Screen
where s.DSN_PM == User.Identity.Name
select s);
TypeOne typeOne = (TypeOne)(from x in _context.TypeOne
where x.Name == User.Identity.Name
select x);
MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
{
Project_Screen = project_Screen,
TypeOne = typeOne
};
return View(myProjectsViewModel);
}
}
}
The issue is that project_Screen
and typeOne
aren't lists or IEnumerable types, which makes sense, but I'm not the syntax to get them to be enumerable.
IF you need to see it, here is my view model:
public class MyProjectsViewModel
{
public List<Project_Screen> Project_Screen { get; set; }
public List<TypeOne> TypeOne { get; set; }
}
And here is the View:
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Project_Screen)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.County)
</td>
<td>
@Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="@item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.TypeOne)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.County)
</td>
<td>
@Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="@item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
Again, the issue is that project_Screen
and typeOne
aren't lists or IEnumerable types IN THE CONTROLLER. They are Lists in actuallity and everywhere EXCEPT the controller but they need to be. The error is on the lines
MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
{
Project_Screen = project_Screen,
TypeOne = typeOne
};
on project_Screen
and typeOne
and reads
cannot implicitly convert type Envapp.Models.DB.Project_Screen to System.Collection.Generic.List<Envapp.Models.DB.Project_Screen>
This appears to be happening because the code there is trying to point to the DB model table for Project_Screen rather than the ViewModel representation of items in the Project_Screen model. How do I fix this?
EDIT 2:
I'm not sure what it is but something in my code seems to be really confusing people. I am posting all of my models for clarification:
Project_Screen.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
#nullable disable
namespace EnvApp.Models.DB
{
public partial class Project_Screen
{
[Key]
public long ID { get; set; }
public string State_Project_Number { get; set; }
public string? Federal_Project_Number { get; set; }
public string Project_Name { get; set; }
public string County { get; set; }
public DateTime? Memo_Date { get; set; }
public string From { get; set; }
public string? Authorization { get; set; }
public string DSN_PM { get; set; }
public string? History { get; set; }
public string History_PM { get; set; }
public bool Review_Exempt_H { get; set; }
public bool SHPO_Approval_H { get; set; }
public string? Archaeology { get; set; }
public string Archaeology_PM { get; set; }
public bool Review_Exempt_A { get; set; }
public bool SHPO_Approval_A { get; set; }
public bool ESA_Key { get; set; }
public bool Crayfish { get; set; }
public bool Crayfish_Habitat_Assessment { get; set; }
public bool NLEB_4D { get; set; }
public bool USFWS { get; set; }
public string USFWS_Type { get; set; }
public bool Mussel_Habitat { get; set; }
public bool Mussel_Stream { get; set; }
public string Within_Airport { get; set; }
public string? ToPo_Quad_Name { get; set; }
public bool Bat_Habitat { get; set; }
public string? Bars { get; set; }
public string Coordinates { get; set; }
public string? Natural_Resources_Notes { get; set; }
public string Adduser { get; set; }
public DateTime? Date_Added { get; set; }
public string Crayfish_Notes { get; set; }
public string Mussel_Notes { get; set; }
}
}
TypeOne.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#nullable disable
namespace EnvApp.Models.DB
{
[Table("Type_One")]
public partial class TypeOne
{
[Key]
public long ID { get; set; }
[MaxLength(50)]
public string State_Project_Number { get; set; }
[MaxLength(50)]
public string Federal_Project_Number { get; set; }
[MaxLength(50)]
public string Name { get; set; }
[MaxLength(50)]
public string Route_Number { get; set; }
public string County { get; set; }
[MaxLength(50)]
public string Work_Type { get; set; }
[MaxLength(100)]
public string Coordinates { get; set; }
public string Project_Description { get; set; }
public bool? Federal_Aid { get; set; }
public bool? Minimal_Project_Verification { get; set; }
[MaxLength(3)]
public string CE_Category { get; set; }
[MaxLength(10)]
public string Amms { get; set; }
public bool Activities_Agreement { get; set; }
public string Arch_RE { get; set; }
public string Hist_RE { get; set; }
public DateTime? Arch_RE_Date { get; set; }
public DateTime? Hist_RE_Date { get; set; }
public bool? Through_Lanes { get; set; }
public bool? Close_Road { get; set; }
public bool? ROW_Acquisition { get; set; }
public bool? Access_Control { get; set; }
public bool? Fifty_Year_Structure { get; set; }
public bool? Agency_Coordination { get; set; }
public bool? IPAC_Screening_Zone { get; set; }
public bool? Section_404_Permit { get; set; }
public bool? Ground_Disturbance { get; set; }
public bool? Waterway { get; set; }
public bool? Special_Use_Permit { get; set; }
public bool? Floodplain { get; set; }
public string Prepared_By { get; set; }
public string Approved_By { get; set; }
public string Adduser { get; set; }
public DateTime? Date_Added { get; set; }
}
}
Natural_ResourcesContext
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
#nullable disable
namespace EnvApp.Models.DB
{
public partial class Natural_ResourcesContext : DbContext
{
public Natural_ResourcesContext()
{
}
public Natural_ResourcesContext(DbContextOptions<Natural_ResourcesContext> options)
: base(options)
{
}
public virtual DbSet<NR_User> NR_Users { get; set; }
public virtual DbSet<Project_Screen> Project_Screen { get; set; }
public virtual DbSet<TypeOne> TypeOne { get; set; }
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
Upvotes: 0
Views: 653
Reputation: 22523
You were close enough. It seems your Project_Screen
and Type_One
should be list kind of class from your view iteration we got to know. If so, then your MyProjectsViewModel
should be like:
View Model:
public class MyProjectsViewModel
{
public List<Project_Screen> ProjectScreen { get; set; }
public List<Type_One> TypeOne { get; set; }
}
Controller:
public ActionResult ViewModelEnumeration()
{
var proScreen = new List<Project_Screen>()
{
new Project_Screen(){ State_Project_Number = 1,Federal_Project_Number =1,Project_Name = "Project-1", County = "USA"},
new Project_Screen(){ State_Project_Number = 2,Federal_Project_Number =2,Project_Name = "Project-2", County = "CA"},
new Project_Screen(){ State_Project_Number = 3,Federal_Project_Number =3,Project_Name = "Project-3", County = "UK"},
};
var typeOne = new List<Type_One>()
{
new Type_One(){ State_Project_Number = 101,Federal_Project_Number =101,Project_Name = "Type-One-Project-1", County = "USA"},
new Type_One(){ State_Project_Number = 102,Federal_Project_Number =102,Project_Name = "Type-One-Project-2", County = "CA"},
new Type_One(){ State_Project_Number = 103,Federal_Project_Number =103,Project_Name = "Type-One-Project-3", County = "UK"},
};
//Bind to View Model
MyProjectsViewModel viewModel = new MyProjectsViewModel();
viewModel.ProjectScreen = proScreen;
viewModel.TypeOne = typeOne;
return View(viewModel);
}
Note: I am binding demo seeder property into the list. Feel free to change as per your requirement.Just getting you into the point.
View:
@model MVCApps.Models.MyProjectsViewModel
@{
ViewData["Title"] = "ViewModelEnumeration";
}
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.ProjectScreen)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.County)
</td>
</tr>
}
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.TypeOne)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.County)
</td>
</tr>
}
</tbody>
</table>
Output:
Note: So according to your scenario you can use like this
@foreach (var item in Model.Project_Screen)
. Additionally, be conscious about your naming convention likeProject_Screen Project_Screen
is confusing either practice likeProject_Screen ProjectScreen
orProjectScreen Project_Screen
.
Hope above steps guide you accordingly. You can enhance your Idea more about this on our official document here
Update:
As per your comment I am also adding the example in case of single object means when you have other than
List
orIEnumerable
View Model:
public class ProjectsScreenTypeOneViewModel
{
public Project_Screen ProjectScreen { get; set; }
public Type_One TypeOne { get; set; }
}
Controller:
public ActionResult ViewModelFromSingleObject()
{
//Binding Project_Screen Object
var _proScreen = new Project_Screen();
_proScreen.Project_Name = "Test Project-202";
_proScreen.State_Project_Number = 1111;
_proScreen.Federal_Project_Number = 11112021;
_proScreen.County = "USA";
//Binding Type_One Object
var _typeOne = new Type_One();
_typeOne.Project_Name = "Test Type One Project-101";
_typeOne.State_Project_Number = 1010;
_typeOne.Federal_Project_Number = 202121;
_typeOne.County = "UK";
//Binding to view model
var _viewModel = new ProjectsScreenTypeOneViewModel();
_viewModel.ProjectScreen = _proScreen;
_viewModel.TypeOne = _typeOne;
return View(_viewModel);
}
View:
@model MVCApps.Models.ProjectsScreenTypeOneViewModel
@{
ViewData["Title"] = "ViewModelFromSingleObject";
}
<h2>ViewModelFromSingleObject</h2>
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
@Html.DisplayFor(modelItem => Model.ProjectScreen.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => Model.ProjectScreen.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => Model.ProjectScreen.Project_Name)
</td>
<td>
@Html.DisplayFor(modelItem => Model.ProjectScreen.County)
</td>
</tr>
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
@Html.DisplayFor(modelItem => Model.TypeOne.State_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => Model.TypeOne.Federal_Project_Number)
</td>
<td>
@Html.DisplayFor(modelItem => Model.TypeOne.Project_Name)
</td>
<td>
@Html.DisplayFor(modelItem => Model.TypeOne.County)
</td>
</tr>
</tbody>
</table>
Output:
Note:
Now as you can see I have added bothsingle
andList
kind of example which will guided you accordingly. If you still encounter any further issue feel free to share.
Upvotes: 1
Reputation: 4711
The error is because you are using foreach on the view model itself, not on the properties you want to enumerate.
For Project_Screen and TypeOne, declare them as an enumerable type (eg. Array, List, IEnumerable, etc).
public class MyProjectsViewModel
{
public IEnumerable<Project_Screen> Project_Screen { get; set; }
public IEnumerable<TypeOne> TypeOne { get; set; }
}
You will need to populate those with a collection of values from the controller
var viewModel = new MyProjectsViewModel();
viewModel.Project_Screen = _context.Project_Screen.Where(x => SOME_CONDITION);
viewModel.TypeOne = _context.TypeOne.Where(x => SOME_CONDITION);
In the view you will enumerate those properties (not the model itself).
@foreach (var item in Model.Project_Screen)
and
@foreach (var item in Model.TypeOne)
Upvotes: 1