How to use ViewBag as list in MVC3 - asp.net-mvc-3

i need to use ViewBag as list inside another ViewBag and i am not understanding how should i do that.
here is my code:
List<string> srclist = new List<string>();
foreach(var item in candidateportfolio)
{
if(item.PortfolioID!=0 && item.ChandidateID!=0)
{
string filepath = Server.MapPath("~/ePortfolio/PortFolioContent/" + HobbyDetailID + "/Assignments/Exhb_" + item.PortfolioID + "_" + item.ChandidateID + ".jpg");
if (System.IO.File.Exists(filepath))
{
srclist.Add(filepath);
}
}
}
ViewBag.Thumbnail = srclist;
candidateportfolio is an object of the class CandidatePortfolio.I fetch the data in the class and check whether its fields are not empty.Then i add the filepath to the list and assign list to Viewbag
Then in View i use it like this:
#foreach (var item in ViewBag.Thumbnail as List<string>)
{
<img src="#item" title="Learner:#ViewBag.FirstName" width="150px" height="150px" border="5" style="align:right;margin:10px"/>
}
Now the problem is i also want to fetch ViewBag.FirstName as list.and i cannot run another list in this.Please tell me how should i do this.

If you want a list containing both FirstName and the path to, say, a photo you can create a new class:
public class ThumbnailModel
{
public string FirstName { get; set; }
public string PhotoPath { get; set; }
}
Now you can add a List<Thumbnail> to the ViewBag.
But I would suggest just creating a strongly typed view with a relvant model containing a List<Thumbnail> property.

user1274646,
your best bet here is to create a public class that contains both the exisiting thumbnail element plus an additional FirstName property. Here's how this might look:
public class CandidateItem{
public string FirstName {get; set;}
public string Filepath {get; set;}
}
then, in your loop, create a new CandidateItem and add it to the list (i.e. List). Here's the amended code:
List<CandidateItem> srclist = new List<CandidateItem>();
foreach(var item in candidateportfolio)
{
if(item.PortfolioID!=0 && item.ChandidateID!=0)
{
CandidateItem candItem = new CandidateItem();
candItem.Filepath = Server.MapPath("~/ePortfolio/PortFolioContent/" + HobbyDetailID + "/Assignments/Exhb_" + item.PortfolioID + "_" + item.ChandidateID + ".jpg");
candItem.FirstName = item.FirstName;
if (System.IO.File.Exists(filepath))
{
srclist.Add(candItem);
}
}
}
ViewBag.Thumbnail = srclist;
then use it in the view as:
#foreach (var item in ViewBag.Thumbnail as List<CandidateItem>)
{
<img src="#item.Filepath" title="Learner:#item.FirstName" width="150px" height="150px" border="5" style="align:right;margin:10px"/>
}

Related

Model binding issues with Kendo complex object

My problem is very similar to this Model binding issues with Kendo objects with complex child properties . The only difference is that i have another level in the object.
My model is:
Public Person
{
public int Id {get;set;}
public string Name {get;set;}
public IEnumerable<Course> Courses {get;set;}
}
public Course
{
public int Id {get;set;}
public string Description {get;set;}
public IEnumerable<Schedule> Schedules {get;set;}
}
Public Schedule
{
public DateTime Init {get;set;}
public DateTime End {get;set;}
}
This model is bound to a KendoGrid. Everything works well, except that Init and End properties are always null when I posted the model.
In the Ajax Datasource :
.Update(update => update.Action("Update", "Controller").Data("serialize"))
.Create(create => create.Action("Create", "Controller").Data("serialize"))
<script>
function serialize(data) {
for (var property in data) {
if ($.isArray(data[property])) {
serializeArray(property, data[property], data);
}
}
};
function serializeArray(prefix, array, result) {
for (var i = 0; i < array.length; i++) {
if ($.isPlainObject(array[i])) {
for (var property in array[i]) {
result[prefix + "[" + i + "]." + property] = array[i][property];
}
}
else {
result[prefix + "[" + i + "]"] = array[i];
}
}
}
</script>
What I have to do to send the properties of the lists schedules?
I had also looked at their serializeArray solution, but it didn't work for me in case of 3 level objects I had. I could have fixed that but then I didn't want to write recursive code. The solution I used is pretty straight-forward and aligned to the problem I had. Its very readable.
I absolutely wish Kendo should do this out of the box for their grid, but they told this when I raised a support question.
"You will need to send the values as additional data in this case because the built-in filtering does not support collection values. To format the data so that it will be bound by the model binder, you should follow the guidelines from my previous reply(dot notation for objects and indexer for arrays)"
Here is my C# ViewModels
//relates to one control value (for e.g. one entry in multi-select)
public class FormUnitFilter
{
public string Operator { get; set; }
public string Field { get; set; }
public string Value { get; set; }
public List<string> ValueList { get; set; }
}
//relates to a set of filters in a combined set (for e.g. the whole multi-select or a radiobutton or date control which appears in a single panel)
public class FormSetFilter
{
public List<FormUnitFilter> Filters { get; set; }
public string LogicalOperator { get; set; }
}
//relates to the whole set of filters present on the screen (for e.g. the filters across different panels)
public class FormWholeFilter
{
public List<FormSetFilter> Filters { get; set; }
public string LogicalOperator { get; set; }
}
here is my js function which converts this json model to a type recognized by MVC controller action parameter.
function buildFilterCriteria() {
var data = {};
if (modelObj) {
//reset the filters
modelObj.FormWholeFilter.Filters.length = 0;
//Assign FormWholeFilter data (outermost object)
data["FormWholeFilter.LogicalOperator"] = modelObj.FormWholeFilter.LogicalOperator;
//now iterate the filters inside FormWholeFilter (1st inner object)
for (var setIndex = 0; setIndex < modelObj.FormWholeFilter.Filters.length; setIndex++) {
var setFilter = modelObj.FormWholeFilter.Filters[setIndex];
data["FormWholeFilter.Filters[" + setIndex + "].LogicalOperator"] = setFilter.LogicalOperator;
//now iterate the filters inside FormSetFilter (2nd inner object)
for (var unitIndex = 0; unitIndex < setFilter.Filters.length; unitIndex++) {
var unitFilter = setFilter.Filters[unitIndex];
data["FormWholeFilter.Filters[" + setIndex + "].Filters[" + unitIndex + "].Operator"] = unitFilter.Operator;
data["FormWholeFilter.Filters[" + setIndex + "].Filters[" + unitIndex + "].Field"] = unitFilter.Field;
data["FormWholeFilter.Filters[" + setIndex + "].Filters[" + unitIndex + "].Value"] = unitFilter.Value;
if (unitFilter.ValueList)
for (var valIndex = 0; valIndex < unitFilter.ValueList.length; valIndex++) {
data["FormWholeFilter.Filters[" + setIndex + "].Filters[" + unitIndex + "].ValueList[" + valIndex + "]"] = unitFilter.ValueList[valIndex];
}
}
}
}
return modelObj && data;
}
Here is my controller action method which takes the Kendo grid datasourcerequest and the FormWholeFilter I pass from JavaScript.
public JsonResult ProcessFilters([DataSourceRequest] DataSourceRequest request, FormWholeFilter formWholeFilter)
{
//Method body
}
Also, when I load the page for the first time, I had assigned the modelObj to the FormWholeFilter blank json like this and thats why I could use this variable in the buildFilterCriteria method:
var modelObj;
$(document).ready(function () {
modelObj = $.parseJSON('#Html.Raw(Json.Encode(#Model))');
});

Displaying Files Name and Link to download in mvc

I have files saved in a Project Folder
D:\Maarjaa\Marjaa\Content\Uploads
Now I want to Display name of these files( not the full URL)
as
lakes of kaghan.jpg
lakes of gilgit.jpg
not as
D:\Maarjaa\Marjaa\Content\Uploads\lakes of kaghan.jpg
Additionally I want to give download links to thes files, so that a user can download these files
Many different ways to do this. Here's one:
Create a class for your files
public class Image
{
public string Name { get; set; }
public string Path { get; set; }
}
and a view model class
public class ViewModel
{
public List<Image> Images { get; set; }
public string Path { get; set; }
}
Then in your controller, populate the view model and the name and path properties for each Image object in the list. You'll need to import the System.IO namespace.
public ActionResult DisplayFilesForDownload( )
{
var viewModel = new ViewModel
{
Path = #"D:\Maarjaa\Marjaa\Content\Uploads",
Images = new List<Image>()
};
var paths = Directory.GetFiles(viewModel.Path).ToList();
foreach (var path in paths)
{
var fileInfo = new FileInfo( path );
var image = new Image
{
Path = path, Name = fileInfo.Name
};
viewModel.Images.Add(image);
}
return View( viewModel);
}
And the method to allow downloads. I am assuming all your files are images. If not, just adjust the MediaTypeName as needed.
public FileResult Download(string filePath, string fileName)
{
var file = File(filePath, System.Net.Mime.MediaTypeNames.Image.Jpeg, fileName);
return file;
}
and finally the view. Image.Name is used to display the shortened file name and Image.Path is used to tell the download method where to fetch the file from.
#model FullyQualified.Path.ToYour.ViewModel
#foreach (var image in Model.Images)
{
<p>#Html.ActionLink(image.Name, "Download", "ControllerName", new{filePath = image.Path, fileName = image.Name}, null)</p>
}
Hope this helps get you on your way.
I did it, In my View
<ul>
#foreach(var Item in(IEnumerable<Marjaa.Data.MultimediaFile>) ViewData["Files"])
{
<li>#System.IO.Path.GetFileName(Item.MultimediaFileUrl) </li>
}
</ul>
From my Controller Just Sent a list to View
IList<MultimediaFile> list = d.MultimediaFiles.Where(l => l.MultmediaId == id).ToList();
ViewData["Files"] = list;

LINQ result is not showing as expected

I'm trying to query for a particular column & to show the item list in view properly one after another. Here is my code:
Controller:
public ActionResult ShowImage()
{
using (var context = new ImageTrialDBEntities())
{
var pathlist = (from s in context.Images
select s.ImageLink).ToList();
var model = new ImageModel();
model.ImageList = pathlist;
return View(model);
}
}
Model:
public class ImageModel
{
public string Image { get; set; }
public IList<string> ImageList { get; set; }
}
View:
<div>
#foreach (var s in Model.ImageList)
{
#Html.DisplayFor(x=>x.ImageList)
<br />
}
</div>
The list is showing like this:
I would like to show one at a time with a break in between. Please help.
Replace
#Html.DisplayFor(x=>x.ImageList)
with
#Html.DisplayFor(x=>s)
You have 2 loops in the view code. Try just printing out the variable s.

Trouble filling and using MultiSelectList/ListBoxFor in ASP.NET MVC 3

I'm trying to adapt the answers for filling a ListBoxFor that has preselected values that I've found here on SO and am having some trouble with the adaptation.
This is one of the questions I've been referring to: here
Here is my class that defines a list object
public class SelectListDTO {
public int ID { get; set; }
public string Name { get; set; }
}
I have a method on a class that fills a List of SelectListDTO items. The CheckRefresh checks to see if the cache is expired, if so it refills the cache. So this method gets my list:
private List<SelectListDTO> GetSelectList() {
CheckRefresh();
var lst = new List<SelectListDTO>(_cache.Count + 1);
_cache.ForEach(item => lst.Add(new SelectListDTO { ID = item.ID, Name = item.Name }));
return lst;
}
My Model is define with these Properties/Methods:
public class MyModel {
[Required]
[Display(Name = "Program Type")]
[Min(1, ErrorMessage = "Please select a Program Type")]
public int[] SelectedProgramTypes { get; set; }
public MultiSelectList ProgramTypes { get; set; }
public MyModel() {
PopulateProgramTypeList();
}
private void PopulateProgramTypeList() {
// Get all available list items
var programTypes = ProgramTypeService.Instance.GetSelectList;
// how to fill multiselectlist with my List<SelectListDTO> items;
ProgramTypes = new MultiSelectList(??)
}
}
1st part of question is from above here^ How to fill the MultiSlectList with my List of SelectListDTO objects
Also in my controller action I am getting the saved items from the DB and will need to pass them to the model as SelectedProgramTypes. This is currently in my action:
public ActionResult Edit(int? id) {
// Code here to validate id and that user is associated with id
lenderProduct = new LenderProduct(id);
var model = BuildModel(lenderProduct); // returns instance or MyModel
var selectedProgramTypes = lenderProduct.ProgramTypes;
foreach (var item in selectedProgramTypes) {
/// How to fill the Model.SelectedProgramTypes array
}
return View(model);
}
2nd part of question is how to get the currently selected items that I read from the DB into the array that can be used by the MultiSelectList in the Model
I feel like I'm this close but am missing some pattern or hopefully just the correct syntax into getting this to work in this way as opposed to the ways I've seen posted here.
I haven't made it to the View yet but from what I've seen that is just as easy as filling a normal DropDownList.
1st part of question is from above here^ How to fill the
MultiSlectList with my List of SelectListDTO objects
ProgramTypes = new MultiSelectList(programTypes.Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
}));
2nd part of question is how to get the currently selected items that I
read from the DB into the array that can be used by the
MultiSelectList in the Model
It's not clear how your LenderProduct class looks like but assuming the ProgramTypes property is just an array of integers you could directly assign it to your view model:
public ActionResult Edit(int? id)
{
// Code here to validate id and that user is associated with id
var lenderProduct = new LenderProduct(id);
var model = BuildModel(lenderProduct); // returns instance or MyModel
model.SelectedProgramTypes = lenderProduct.ProgramTypes;
return View(model);
}
and if it is an array of some complex object you could select the corresponding property that contains the id:
public ActionResult Edit(int? id)
{
// Code here to validate id and that user is associated with id
var lenderProduct = new LenderProduct(id);
var model = BuildModel(lenderProduct); // returns instance or MyModel
model.SelectedProgramTypes = lenderProduct.ProgramTypes.Select(x => x.ID).ToArray();
return View(model);
}

Best way to sort a DropDownList in MVC3 / Razor using helper method

Hi so I'm pretty new to MVC3 and Razor and I've been trying to get my head around it the past few days. I've been given a task by my project architect to create a helper method that sorts a drop down list in an MVC View. I have a View that retrieves various data from a Controller and I'm returning some values that I want to appear in a drop down list. I've been told not to sort it in the Controller and also to pass the field that we want to sort by into the helper method. I could do it like below but the architect wants to keep the view free of c sharp code:
#Html.DropDownListFor(model => model.StudyName, new SelectList(ViewBag.StudyTypes, "Value", "Text").OrderBy(l => l.Text))
So I've created some sample code and some extension methods to try and get it to work. My idea is to replicate the existing Html.DropDownList method and allow the passing of 'object htmlAttributes' so I can set the style as part of the method call.
Here's my code so far. I'm returning the data for the drop down in ViewBag.StudyTypes in the Edit Controller method:
public ActionResult Edit(int id)
{
IEnumerable<SelectListItem> mySelectList = new List<SelectListItem>();
IList<SelectListItem> myList = new List<SelectListItem>();
for (int i = 0; i < 5; i++)
{
myList.Add(new SelectListItem()
{ Value = i.ToString(), Text = "My Item " + i.ToString(), Selected = i == 2 }
);
}
mySelectList = myList;
ViewBag.StudyTypes = mySelectList;
StudyDefinition studydefinition = db.StudyDefinitions.Find(id);
return View(studydefinition);
}
Here's my View code:
#model MyStudyWeb.Models.StudyDefinition
#using MyStudyWeb.Helpers
#{
ViewBag.Mode = "Edit";
}
<div>
#Html.DropDownListSorted(new SelectList(ViewBag.StudyTypes, "Value", "Text"))<br />
#Html.DropDownListSorted("MyList", new SelectList(ViewBag.StudyTypes, "Value", "Text"))<br />
</div>
Finally below are the extension methods I'm trying to get to work. The first extension method does nothing, I just get a blank space at that point in the View. The second method kind of works but it's ugly. For the 3rd method I don't know how to specify an 'order by' parameter as the OrderBy on an IEnumerable expects a Linq expression.
namespace StudyDefinition.Helpers
{
public static class HtmlHelperExtensions
{
// 1st sort method: sort the passed in list and return a new sorted list
public static SelectList DropDownListSorted(this HtmlHelper helper, IEnumerable<SelectListItem> selectList)
{
var x = new SelectList(selectList.ToList()).OrderBy(l => l.Text);
return x as SelectList;
}
// 2nd sort method: return IHtml string and create <select> list manually
public static IHtmlString DropDownListSorted(this HtmlHelper helper, string name, SelectList selectList)
{
StringBuilder output = new StringBuilder();
(selectList).OrderBy(l => l.Text);
output.Append("<select id=" + name + " name=" + name + ">");
foreach (var item in selectList)
{
output.Append("<option value=" + item.Value.ToString() + ">" + item.Text + "</option>");
}
output.Append("</select>");
return MvcHtmlString.Create(output.ToString());
}
// 3rd sort method: pass in order by parameter - how do I use this?
public static IHtmlString DropDownListSorted(this HtmlHelper helper, string name, SelectList selectList, string orderBy)
{
StringBuilder output = new StringBuilder();
//How do I use the orderBy parameter?
(selectList).OrderBy(l => l.Text);
output.Append("<select id=" + name + " name=" + name + ">");
foreach (var item in selectList)
{
output.Append("<option value=" + item.Value.ToString() + ">" + item.Text + "</option>");
}
output.Append("</select>");
return MvcHtmlString.Create(output.ToString());
}
}
}
I really don't know the best approach to take, there may be a much simpler way that I'm totally missing and I might be at the point where I can't see the wood for the trees anymore. Some questions
Should I return a SelectList or an MvcHtmlString, or something else entirely?
For the first extension method how do I get the returned SelectList to render in the View?
How to I pass in a parameter to my extension methods that specifies the sort order?
How do I pass an 'object htmlAttributes' parameter, and how do I apply this object / parameter to the SelectList?
If anyone has some ideas or suggestions then I'd appreciate some feedback :)
The first and most important part of your code would be to get rid of any ViewBag/ViewData (which I personally consider as cancer for MVC applications) and use view models and strongly typed views.
So let's start by defining a view model which would represent the data our view will be working with (a dropdownlistg in this example):
public class MyViewModel
{
public string SelectedItem { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
then we could have a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// I am explicitly putting some items out of order
Items = new[]
{
new SelectListItem { Value = "5", Text = "Item 5" },
new SelectListItem { Value = "1", Text = "Item 1" },
new SelectListItem { Value = "3", Text = "Item 3" },
new SelectListItem { Value = "4", Text = "Item 4" },
}
};
return View(model);
}
}
and a view:
#model MyViewModel
#Html.DropDownListForSorted(
x => x.SelectedItem,
Model.Items,
new { #class = "foo" }
)
and finally the last piece is the helper method which will sort the dropdown by value (you could adapt it to sort by text):
public static class HtmlExtensions
{
public static IHtmlString DropDownListForSorted<TModel, TProperty>(
this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> items,
object htmlAttributes
)
{
var model = helper.ViewData.Model;
var orderedItems = items.OrderBy(x => x.Value);
return helper.DropDownListFor(
expression,
new SelectList(orderedItems, "Value", "Text"),
htmlAttributes
);
}
}
Just add in the sorting before you return the items to the dropdown list.
Do this:
Models: StudyViewModel.cs
public class StudyViewModel {
public string StudyName { get; set; }
public string StudyTypes { get; set; }
}
Controller: StudyController.cs
using System.Web.Mvc;
public class StudyController
{
public List<SelectListItem> studyTypes()
{
List<SelectListItem> itemList = new List<SelectListItem>();
for (var i=0; i<5; i++)
{
itemList.Add = new SelectListItem({
Value = i.ToString();
Text = "My Item";
});
}
// You can sort here....
List<SelectListItem> sortedList = itemList.OrderBy(x=>x.Text);
return sortedList;
}
public ActionResult Edit(int id)
{
//You won't need this because you get it using your
//controller's routine, instead
//ViewBag.StudyTypes = studySlots.OrderBy(e => e.Value);
//-- unless you need to add these values to the model for
// some reason (outside of filling the ddl), in which case....
// StudyViewModel svm = new StudyViewModel();
// svm.StudyTypes = studySlots.OrderBy(e => e.Value);
// svm.StudyName = "My Item";
// return View(svm);
// Otherwise, just....
return View();
}
}
View: Edit.cshtml
#Html.DropDownListFor(model => model.StudyName)
.OptionLabel('Select...')
.DataTextField('Text')
.DataValueField('Value')
.Datasource(source =>
{
// This is where you populate your data from the controller
source.Read(read =>
{
read.Action("studyTypes", "Study");
});
})
.Value(Model.StudyName != null ? Model.StudyName.ToString() : "")
)
This way will avoid ViewBags and just use a function to fill in the values, directly.
If you are using a database you can use a query to define the sort element
using (BDMMContext dataContext = new BDMMContext())
{
foreach (Arquiteto arq in dataContext.Arquitetos.SqlQuery("SELECT * FROM Arquitetos ORDER BY Nome"))
{
SelectListItem selectItem = new SelectListItem { Text = arq.Nome, Value = arq.Arquiteto_Id.ToString() };
//
list.Add(selectItem);
}
}

Resources