Convert IList<string> to MVC.SelectListItem needs explicit casting - model-view-controller

I am calling a project (WCF, but that shouldn't matter) that consumes a IList , with MVC 3 (which really should not matter either obviously) I want to convert a single column List of strings (IList which is just a list of Countries) into a List
Hard Coded list I have done like this and they work fine:
public List<SelectListItem> mothermarriedatdelivery = new List<SelectListItem>();
mothermarriedatdelivery.Add(new SelectListItem() { Text = "Yes", Value = "1" });
However, now I am trying to convert this code:
public List<SelectListItem> BirthPlace { get; set; }
BirthPlace = new List<SelectListItem>();
GetHomeRepository repo = new GetHomeRepository();
BirthPlace = repo.GetCountries();
I need to implicitly convert from the List to SelectListItem, anyone do this? Yes.. I have search and found several examples, but none that really fit my specific need.

You can use LINQ as such:
BirthPlace = repo.GetCountries()
.Select(x => new SelectListItem { Text = x, Value = x })
.ToList();
Or I think you can just use one of SelectList's constructors:
public SelectList BirthPlace { get; set; }
BirthPlace = new SelectList(repo.GetCountries());

In Controller ,
var result = proxy.GetAllLocations();
ViewBag.Area = result.Where(p => p.ParentId == null).Select(p => new SelectListItem { Text = p.LocationName, Value = p.LocationId.ToString() }).ToList();
ViewBag.Locations = result.Where(p => p.ParentId != null).Select(p => new SelectListItem { Text = p.LocationName, Value = p.LocationId.ToString() }).ToList();
return View();
In View ,
#Html.DropDownList("LocationName", ViewData["Area"] as IEnumerable<SelectListItem>)

Related

LINQ Query - How i can make my query better?

I have written following LINQ query to return list and then iterating list separately to convert time into hours and taking sum of hours for each list item.
I am sure this might not be the right away as it send three database calls.
Can i re-write it in a better way e.g. GroupBy or by some other way to assign data to model, converting IdleTime into hours and than taking sum of IdleTime??
Model Class
public class TestModel
{
public string TaskSummary { get; set; }
public string LocationName { get; set; }
public float IdleTime { get; set; }
public string Description { get; set; }
public float IdleTimeSum { get; set; }
public Guid TaskId { get; set; }
}
LINQ Query
List<TestModel> list = _context.Time
.Include(x => x.Report)
.Include(x => x.Report.Task)
.Include(x => x.Report.Task.Location)
.Where(x => taskIds.Contains(x.Report.TaskId))
.Select(x => new TestModel
{
TaskSummary = x.Report.Task.Summary,
LocationName = x.Report.Task.Location.Name,
IdleTime = x.Duration,
Description = x.Description,
TaskId = x.Report.TaskId,
}).ToList();
How i am converting into hours?
foreach (var item in list)
item.IdleTime = item. IdleTime / 60;
How I am taking sum?
foreach (var item in list)
item.IdleTimeSum = item. IdleTime;
Just add those to your projection:
.Select(x => new TestModel
{
TaskSummary = x.Report.Task.Summary,
LocationName = x.Report.Task.Location.Name,
IdleTime = x.Duration / 60.0f,
Description = x.Description,
TaskId = x.Report.TaskId,
NPTHoursSum = x.Duration / 60.0f,
}).ToList();
Although since you're not showing where you actually sum anything I suspect there's more to the problem than that.
Yeah Select is a projection function, you can just do those operations in your select.
.Select(x => new TestModel
{
TaskSummary = x.Report.Task.Summary,
LocationName = x.Report.Task.Location.Name,
IdleTime = x.Duration /60.0f,
NPTHoursSum = x.Duration / 60.0f,
Description = x.Description,
TaskId = x.Report.TaskId,
}).ToList();
If you're using LINQ to SQL then the division operation will probably occur at the db. If you actually want to do a sum it would have to be in a different query or as a sub query or something.\

LINQ to return list of Object filtered on a property of a Child object in nested List<>

I'm looking for some help with a LINQ query to filter on a property/enum of a custom object which is in a nested List, and want to maintain the parent object in return list.
For example/clarity/sample code, I have a parent object, which has in it a List based on class and enum below:
public class Stage {
public String Name { get; set;}
public List<Evaluation> MyEvaluations { get; set;}
}
public class Evaluation {
public float Result { get; set; }
public enumResultType ResultType { get; set; }
}
public enum enumResultType {
A,B,C
}
One can simulate sample data along those lines with something like:
List<Stage> ParentList = new List<Stage>();
Stage Stage1 = new Stage() { Name = "Stage1",
MyEvaluations = new List<Evaluation>() {
new Evaluation() { ResultType = enumResultType.A, Result=5 },
new Evaluation() { ResultType = enumResultType.B, Result=10},
new Evaluation() { ResultType = enumResultType.B, Result=11},
new Evaluation() { ResultType = enumResultType.C, Result=5}
}};
Stage Stage2 = new Stage() { Name = "Stage2",
MyEvaluations = new List<Evaluation>() {
new Evaluation() { ResultType = enumResultType.A, Result=10},
new Evaluation() { ResultType = enumResultType.B, Result=20},
new Evaluation() { ResultType = enumResultType.C, Result=20}}};
ParentList.Add(Stage1);
ParentList.Add(Stage2);
What I want to be able to do, via LINQ, is to select from the Parentlist object, all the items with only a filtered list where the ResultType in the Evaluations List matches a proper condition...
I don't want to repeat the parent object multiple times (seen selectmany), but rather a filtered down list of the MyEvaluations where the ResultType matches, and if this list has items (it would) return it with the parent.
I've played with:
ParentList.Select(x => x.MyEvaluations.FindAll(y => y.ResultType==enumResultType.B)).ToList();
however this returns only the inner list... whereas
ParentList.Where(x => x.MyEvaluations.Any(y => y.ResultType==enumResultType.B)).ToList();
returns ANY.. however I am missing how to get the list of MyEvaluations to be filtered down..
In my Example/sample data, I would like to query ParentList for all situations where ResultType = enumResultType.B;
So I would expect to get back a list of the same type, but without "Evaluation" which are equal to ResultType.A or .C
Based on dummy data, I would expect to be getting something which would have:
returnList.Count() - 2 items (Stage1 / Stage2) and within that Stage1 --> foreach (item.Result : 10, 11 Stage2 --> foreach (item.Result : 20
Can this be done without going to projections in new anonymous types as I would like to keep the list nice and clean as used later on in DataBinding and I iterate over many ResultTypes?
Feel like I'm missing something fairly simple, but fairly new to LINQ and lambda expressions.
Did you try these approaches already? Or is this not what you're looking for ?
//creating a new list
var answer = (from p in ParentList
select new Stage(){
Name = p.Name,
MyEvaluations = p.MyEvaluations.Where(e => e.ResultType == enumResultType.B).ToList()
}).ToList();
//in place replacement
ParentList.ForEach(p => p.MyEvaluations = p.MyEvaluations.Where(e => e.ResultType == enumResultType.B).ToList());

values for DropDownList items

I have follwoing code
#Html.DropDownList("optionsforuser", new SelectList(new[] { "Option1", "Option2", "Option3" }), "Select")
Is there anyway to initialize a value of 100 for Option1, 200 for Option2, 250 for Option3 etc within SelectList?
Try using this Extension:
#Html.DropDownList("optionsforuser",
new SelectList(new Dictionary<string, int>
{
{"Option1", 100},
{"Option2", 200},
{"Option3", 250}
},
"Value", "Key")
)
and pass it a Dictionary<string, int> with the dataValueField and dataTextField populated with your values and text
SelectExtensions.DropDownList Method (HtmlHelper, String, IEnumerable(Of SelectListItem))
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> selectList
)
SelectList Constructor (IEnumerable, String, String)
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
For situations where I just want to hard-code select list items (i.e. not get them from some pre-defined collection), I use this handy little class:
public class BetterSelectList : List<SelectListItem>
{
public void Add(string text, object value, bool selected = false) {
this.Add(new SelectListItem {
Text = text,
Value = value.ToString(),
Selected = selected
});
}
}
Why is it "better"? It implements IEnumerable and has a multi-parameter Add method, which is all you need for the C# compiler to allow you to use dictionary-style initializers, resulting in about the most noise-free initialization possible:
var optionsForUser = new BetterSelectList {
{ "Option1", 100, true },
{ "Option2", 200 },
{ "Option3", 250 }
};
Yes you set text and value
var selections = new List<SelectListItem>();
selections.Add(new SelectListItem() { Text = "Option1", Value = "100" });
selections.Add(new SelectListItem() { Text = "Option2", Value ="200" });
Here is an MSDN article on select lists: select list
You can do it in your view like that as the others have posted, but can't you do it in the controller instead?
For example, In your view model:
public class ViewModel()
{
public List<SelectListItem> OptionsForUser{ get; set; }
}
In your controller:
var optionsForUser = new List<SelectListItem>();
optionsForUser.Add(new SelectListItem { Text = "Option1", Value = "100"});
optionsForUser.Add(new SelectListItem { Text = "Option2", Value = "200"});
optionsForUser.Add(new SelectListItem { Text = "Option3", Value = "250"});
var viewmodel = new ViewModel();
viewmodel.OptionsForUser = optionsForUser;
return view(viewmodel);
then in your view:
#Html.DropDownList("optionsforuser", Model.OptionsForUser);
Those other solutions will work too, I just think its not very "clean" to initialise your dropdown list in your view like that. But its probably a matter of taste

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);
}
}

How to dynamically choose two fields from a Linq query as a result

If you have a simple Linq query like:
var result = from record in db.Customer
select new { Text = record.Name,
Value = record.ID.ToString() };
which is returning an object that can be mapped to a Drop Down List, is it possible to dynamically specify which fields map to Text and Value?
Of course, you could do a big case (switch) statement, then code each Linq query separately but this isn't very elegant. What would be nice would be something like:
(pseudo code)
var myTextField = db.Customer["Name"]; // Could be an enumeration??
var myValueField = db.Customer["ID"]; // Idea: choose the field outside the query
var result = from record in db.Customer
select new { Text = myTextField,
Value = myValueField };
Right way to do this is with closures.
Func<Customer, string> myTextField = (Customer c) => c["Name"];
Func<Customer, int> myValueField = (Customer c) => c["ID"];
var result = from record in db.Customer
select new { Text = myTextField(record),
Value = myValueField(record) };
The one limitation is that your definition of myTextField always needs to return a string.
You could try something like
class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
var dict = new Dictionary<string, Func<Customer, string>>
{ { "ID", (Customer c) => c.ID.ToString() },
{ "Name", (Customer c) => c.Name},
{ "Surname", (Customer c) => c.Surname } };
List<Customer> rows = new List<Customer>();
rows.Add(new Customer { ID = 1, Name = "Foo", Surname = "Bar"});
var list = from r in rows
select new { Text = dict["ID"](r), Value = dict["Name"](r) };
To try to access the properties dynamically, you could try something like
var dict = new Dictionary<string, Func<Customer, string>>
{ { "ID", (Customer c) => c.GetType().GetProperty("ID").GetValue(c,null).ToString() },
{ "Name", (Customer c) => c.GetType().GetProperty("Name").GetValue(c,null).ToString()},
{ "Surname", (Customer c) => c.GetType().GetProperty("Surname").GetValue(c,null).ToString() } };

Resources