Displaying data from ViewBag into table? - c#

I'm trying to retrieve a list of file info for .dll files from a specific directory to display on a ASP.NET webpage. The info I want displayed is the file name, the date it was last modified and the version.
So far I have the data being stored in a ViewBag and being displayed in the view, however it's messy and I want it to be displayed in a table.
Is there a way to take data from a ViewBag and place it in a table or is there better way than using the ViewBag?
This is the code I have for the View so far:
#using System.Diagnostics
#{
ViewBag.Title = "Versions";
}
<h2>Versions</h2></br>
<h3>File Name Last Modified Version</h3>
#ViewBag.FileList
#for(int i =0; i < ViewBag.FileList.Length;i++)
{
<p>
#ViewBag.FileList[i];
#{ FileInfo f = new FileInfo(ViewBag.FileList[i]);
<table>
<td><tr>#f.Name</tr></td>
<td><tr> #f.LastAccessTime</tr></td>
</table>
FileVersionInfo currentVersion = FileVersionInfo.GetVersionInfo(ViewBag.FileList[i]);
#currentVersion.FileVersion
}
</p>
}

ViewBag should not be exploited this way. Use a View Model
In your controller's action pass the data like this,
public ActionResult Files()
{
List<FileInfo> fileNames = ...get file names
return View(fileNames);
}
In your view,
Right at the top, define the type of object
#model IEnumerable<System.IO.FileInfo>
Your table should be layed out in a way similar to the below.
<table>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#item.Name</td>
<td>#item.LastAccessTime</td>
</tr>
}
</tbody>
</table>

Related

How do I select a table row and grab data from it in razor?

I am new to coding, so sorry in advanced if this is simple.
I have a table that is populated through a foreach loop, iterating through a list of my model's type, which contains all of my properties. This is how my table body looks:
<tbody>
#foreach (var row in Model.myModel)
{
<tr>
<td>#row.Year</td>
<td>#row.ID</td>
<td>#row.User</td>
</tr>
}
</tbody>
There is a way that I want to do this but I am not sure how. I want to be able to click on the row and return the index number, so then I can just get the value straight from the list directly from the list. Is there a way to do this? Or should I be going about this another way?
I am working on a asp.net core web application btw. This is in my Index.cshtml file and so far I only have some code in my Index.cshtml.cs file to get the data from sql server into the list I am using to fill this table.
You can try this:
<tbody>
#foreach (var row in myModel)
{
<tr #onclick="#(() => Edit(#row.ID))">
<td>#row.Year</td>
<td>#row.ID</td>
<td>#row.User</td>
</tr>
}
</tbody>
and add this below:
#code {
private List<Model> myModel = new List<Model>();
private void Edit(int ID)
{
Console.WriteLine("You clicked" + ID);
}
}

Dynamically Access Properties in ASP.NET Razor

I'm trying to access the properties of a class dynamically in ASP.NET Razor when generating an HTML Table. This problem is normally easily solved with reflection, but the #Html.DisplayFor method is giving me issues.
I am attempting to generate an HTML table that has 3 cells per row, with the title of the item in bold as the first line of the cell, and the value of the item in the second line of the cell. The contents of the table should not include cells which are on the 'Excluded Fields' list, and I do not want to have to statically reference each column.
<table class="blpSecurityTable">
<tr>
#{
int _rowCount = 0;
foreach (var property in item.GetType().GetProperties())
{
#if (!Model.ExcludedFields.Contains(#property.Name))
{
dynamic test = #property.GetValue(item);
<td><b>#Html.DisplayFor(m => #property.Name)</b><br />#Html.DisplayFor(m => #test)</td>
_rowCount++;
}
#if (_rowCount % numCols == 0)
{
#:</tr><tr>
}
}
}
</tr>
</table>
I've tried calling #Html.DisplayFor(m => #property.GetValue(item)) but that just creates a runtime error. I can simply call #property.GetValue(item) and the value displays, but this is not ideal because I use display templates to do things like set dates to the ShortDateString format.
I understand that DisplayFor is using reflection to determine the type of the property, and that is why I am trying to use the dynamic variable to facilitate reflection for the method. However, when I run the method, it throws errors indicating the variable is not a generic parameter, and therefore cannot share its attributes. The resulting page has mostly blank values, and some cells filled in with unexpected descriptive information.
I feel like I'm getting close, but I don't know how to proceed. The page won't look right if I don't pass the values into an HTML display method, and I cannot think of any other way to get the type of table I want to be generated. Thoughts?
The issue is solved by creating a Display Template for the Security object, which then allowed me to properly use the #Html.Display Method, because the Model for the Display Template has an entry for the property.
Here is what the page code looks like now:
Display Template
#model Interface.Models.Security
#{int numCols = 3;}
<table class="blpSecurityTable">
<tr>
#{
int _rowCount = 0;
foreach (var property in Model.GetType().GetProperties())
{
#if (!BLPDLModel.ExcludedFields.Contains(#property.Name))
{
<td><b>#Html.DisplayFor(m => #property.Name)</b><br />#Html.Display(property.Name)</td>
_rowCount++;
}
#if (_rowCount % numCols == 0)
{
#:</tr><tr>
}
}
}
</tr>
</table>
Razor Page
#foreach (var item in Model.Security)
{
<div class="blpSecurityItem">
<button type="button" class="collapsible">{button text}</button>
#{
<div class="collapsible-content">
<hr />
#Html.DisplayFor(m => item)
</div>
}
</div>
Replace #Html.DisplayFor(m => #test) with #Html.Display(property.Name)
and your model property for date should have [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}")] or anything you like

Proper way of binding a dictionary to a cshtml table

My story is: I'm working in a asp.net MVC project. I have two Model's list, reprezented like this:
private Dictionary<string, List<Tuple<string, string>>> _foldersName_NoRecords = new Dictionary<string, List<Tuple<string, string>>>();
private List<string> _totalNoOfDates = new List<string>();
after I fill those lists(as I've seen after debug the fill goes perfectly), I pass them to a ViewBag for accessing them in the view. The problem is that the lists are not displayed in the order they are filled in and are rather overridden.
The code from the view is:
<thead>
<tr>
<th>
Folder Name
#foreach(var date in #ViewBag.dateList)
{
<td>#date</td>
}
</th>
</tr>
</thead>
<tbody>
#foreach(var tupleKey in #ViewBag.statisticsList.Keys)
{
<tr>
<td> #tupleKey </td>
#foreach (var tupleItem in #ViewBag.statisticsList[tupleKey])
{
foreach (var date in #ViewBag.dateList)
{
if (tupleItem.Item1 == date)
{
<td>#tupleItem.Item2</td>
}
}
}
</tr>
}
</tbody>
for example: #tupleItem.Item2 is not displayed to the date that it belongs when a new key is added(the data stored from the lists is extracted from txt files). Anyone have any idea of better displaying this data?
Since Tuple has many overloaded options, why not have a third DateTime parameter that you can use to link the contents of the Tuple to the contents of the date? If you want to keep the lists separate, ensure the ordering on loading the dictionary/list is the same; sounds like something is getting out of order.

Why does my view always expect 1 specific viewmodel? [duplicate]

This question already has answers here:
The model item passed into the dictionary is of type .. but this dictionary requires a model item of type
(7 answers)
Closed 6 years ago.
It seems like this question has been asked and asnwered a lot on this site, but I still cannot seem to get my problem solved. I'm getting the The model item passed into the dictionary is of type 'X', but this dictionary requires a model item of type 'Y' error, even though I'm pretty sure my code is pointing to the right place and receiving the correct viewModel.
View (Index)
#model EveryNationRandburg.ViewModels.AllUsers
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Church Members</h2>
<p>#Html.ActionLink("New Member", "Register", "Account", null, new { #class = "btn btn-primary" })</p>
<table class="table table-bordered table-hover" id="kerkmembers">
<thead>
<tr>
<th>Member</th>
<th>Email</th>
<th>Contact Number</th>
</tr>
</thead>
<tbody>
#foreach (var member in Model.AlleKerkMembers)
{
<tr>
<td>#Html.ActionLink(#member.UserName, "Edit", "KerkMember", new {id = #member.Id}, null)</td>
<td>#member.Email</td>
<td>#member.PhoneNumber</td>
</tr>
}
</tbody>
</table>
#section scripts
{
<script>
$(document).ready(function (){
$("#kerkmembers").DataTable();
})
</script>
}
ViewModel
public class AllUsers
{
public List<ApplicationUser> AlleKerkMembers = new List<ApplicationUser>();
}
Account Controller
public ActionResult Index()
{
var viewModel = new AllUsers
{
AlleKerkMembers = _context.Users.ToList()
};
return View(viewModel);
}
StackTrace
InvalidOperationException: The model item passed into the dictionary is of type 'EveryNationRandburg.ViewModels.AllUsers', but this dictionary requires a model item of type 'EveryNationRandburg.ViewModels.KonnekGroepViewModel'.
What is slightly different for my problem is that whenever I try to send a viewModel to a view, I always get the error saying it is expecting item of type 'Y' (always the same one, no matter what model I declare at the top of my view)
First thing I'd suggest is to attach a debugger to your code and see values you are handling. With debugger you can see call stack which we can't see here.
Where do you use result for return View(viewModel); ?
You don't have listing for your view's constructor.
What is the type of object your view is expecting?
Should be AllUsers since you are passing AllUsers object to it.
You can try using explicit types instead of var to be sure you are passing right object type. Code would be easier to read too.
Please attach your debugger and try to solve it out that way.

Access the value of Checkboxes from controller - DB

I am trying to make the user update the value of the check box from DB.
The view lists all the available workers in DB.
but when i try to access the list of checkbox, the view passes wrong data
ex. there're only 3 checkbox, and it sends 5 items of true/false value.
I really appreciate any assistance.
View Sample Code
#using (Html.BeginForm("UpdateWorkersForTask", "Tasks", FormMethod.Post))
{
<table>
<tr>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.isChecked)
#Html.CheckBox("WorkersID", item.isChecked)
</tr>
}
and the controler is
[HttpPost]
public ActionResult UpdateWorkersForTask(IEnumerable<bool> WorkersID, IEnumerable<string> hiddens) { }
Because by design #Html.CheckBox and #Html.CheckBoxFor render 2 inputs, a checkbox and a hidden input. If you inspect the html you will see something like
<input name="WorkersID" type="checkbox" value="true">
<input name="WorkersID" type="hidden" value="false">
The reason for this is that unchecked checkboxes do not post back. so the second input ensures a value is posted back. In the case where the checkbox is checked the DefaultModelBinderreads the first value which is true and ignores the second value (because it has the same name).
In your case you are not binding to you model, instead you are just reading all inputs with the name WorkersID. If you have 3 items but 5 values are posted back, it would mean that you checked 2 of the boxes.
To correct this, modify your view and action method as follows (note your model needs to be IList so the for loop works, or alternatively you can use a custom EditorTemplate
View
for(int i = 0; i < Model.Count i++)
{
#Html.CheckBoxFor(m => m[i].WorkersID)
}
Controller
[HttpPost]
ActionResult UpdateWorkersForTask(IEnumerable<YourModelType> model)
{
foreach(YourModelType item in model)
{
// do something with the value of item.WorkersID

Categories