Dropdownlist with unknown amount of values - c#

I have a dropdownlistand I would like to bind my Dictionaryto it where the keys are the displayed items and the values are stored in the value attribute tag.
I found this:
bind-html-dropdownlist-with-static-items
But it doesn't allow for an unknown number of items to be bound as you have to manually enter the SelectListItem. I tried this:
#Html.DropDownList("OverrideConfigList", new List<SelectListItem>
{
for(KeyValuePair<string, string> entry in Model.IdentifiFIConfiguration.Config.Configuration)
{
new SelectListItem { Text = entry.Key, Value = entry.Value}
}
})
But that didn't work either. Any suggestions?
Edit:
My model class looks basically like this:
public class DefaultConfigurationModel
{
public IdentifiFIConfiguration IdentifiFIConfiguration { get; set; }
public String FiKeySelection { get; set; }
public List<String> FiConfigKeys
{
get
{
if (IdentifiFIConfiguration.Config == null)
{
return null;
}
List<string> fiConfigKeys = new List<string>();
foreach (KeyValuePair<string, string> entry in IdentifiFIConfiguration.Config.Configuration)
{
fiConfigKeys.Add(entry.Key);
}
return fiConfigKeys;
}
}
}
IdentifiFIConfiguration holds Config which looks like this:
public class IdentifiConfiguration
{
public Dictionary<String, String> Configuration { get; set; }
public static IdentifiConfiguration DeserializeMapFromXML(string xml)
{
Dictionary<string, string> config = new Dictionary<string, string>();
XmlDocument configDoc = new XmlDocument();
configDoc.LoadXml(xml);
foreach (XmlNode node in configDoc.SelectNodes("/xml/*"))
{
config[node.Name] = node.InnerText;
}
IdentifiConfiguration identifiConfiguration = new IdentifiConfiguration()
{
Configuration = config
};
return identifiConfiguration;
}
}

Your attempt is close, but the syntax is wrong. You can't execute a for loop in a list initializer like that.
Essentially, what you're trying to do is transform a collection of one thing (key/value pairs) to a collection of another thing (SelectListItems). You can do that with a LINQ select:
Model.IdentifiFIConfiguration.Config.Configuration.Select(c => new SelectListItem { Text = c.Key, Value = c.Value })
You may optionally need to add a .ToList() or .ToArray() at the end either for static typing or to materialize the collection sooner, but that wouldn't affect the logic of the statement.
This transformation would result in the list of SelectListItems that you want:
#Html.DropDownList(
"OverrideConfigList",
Model.IdentifiFIConfiguration.Config.Configuration.Select(c => new SelectListItem { Text = c.Key, Value = c.Value })
)

you cannot bind a dropdown list to a dictionnary
you need scalar property to bind select value
also you need a collection to bind a dropdownlist
you could do this but that ugly
#Html.DropDownList("SelectedItemValue", new SelectList(MyDictionary, "Key", "Value"))

Related

How to address specific element in list

I want to create "list of list of list". It should be:
Group (has a list of Members)
Member (has a Name and list of Properties)
Property (has Name and Value)
What I want is to have a possibility to add Property into Member (specified by its name) inside defined Group. Someting like this:
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
I have trouble achieving this using list... I found class Hashable, but I am not sure if this is usable... and cannot make it works too...
Thank for any suggestion :)
Well, I suggest you create a custom class instead of your approach. But otherwise you can use a Dictionary.
var properties = new Dictionary<string, string>();
properties.Add("Prop1", "Value");
var members = new Dictionary<string, Dictionary<string, string>>();
members.Add("Member1", properties);
var group = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
group.Add("GroupName", members);
public class Group
{
public Group()
{
Members = new List<Member>();
}
public IEnumerable<Member> Members { get; set; }
}
public class Member
{
public Member()
{
Properties = new Dictionary<string, string>();
}
public string Name { get; set; }
IDictionary<string, string> Properties { get; set; }
}
The dictionary can take a key and a value, and the key should be unique.
You can also create a class property if you want to add another thing beside the name and the value
I would use indexers.
Here's a partial implementation:
class Group
{
private List<Member> _members;
public string this
{
get
{
return _members.Find(m => m.Name == value);
}
// You can also implement set here if you want...
}
}
class Member
{
private List<Property> _properties;
public string Name {get;set;}
public string this
{
get
{
return _properties.Find(m => m.Name == value);
}
}
}
class Property
{
public string Name {get;set;}
public string Value {get;set;}
}
And the usage:
var g = new Group();
g[memberName][propertyName].Value = someValue;
Note: This implementation is partial! it still needs constructor logic and any other logic you might need.
Likely the best solution is to use the C# class Dictionary - as suggested by zetawars, or a custom class - as suggested by Zohar Peled, or some mix of the two - as suggested by gandalf.
However, in order to use syntax similar to what is requested in the question...
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
You can abuse ExpandoObject and Action, and do something awesome like this:
dynamic membersgroup = new ExpandoObject();
var getNewMemberObject = new Func<dynamic>(() =>
{
dynamic memberObject = new ExpandoObject();
var addPropertyAction = new Action<string, string>((propertyName, propertyValue) =>
{
((IDictionary<string, object>)memberObject).Add(propertyName, propertyValue);
});
memberObject.AddProperty = addPropertyAction;
return memberObject;
});
var addNewMemberAction = new Action<string>((memberName) =>
{
((IDictionary<string, object>)membersgroup).Add(memberName, getNewMemberObject());
});
membersgroup.AddNewMember = addNewMemberAction;
string memberXYZ = nameof(memberXYZ);
string nameXYZ = nameof(nameXYZ);
string valueXYZ = nameof(valueXYZ);
// look we did it!
membersgroup.AddNewMember(memberXYZ);
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ);
// and it actually works
var actualValue = membersgroup.memberXYZ.nameXYZ;
Console.WriteLine(actualValue); // "valueXYZ"
(for science of course)

To check a list and populate the value accordingly

I have a string list with values. I need to assign a value to a list based on the particular index of the string. Below is my code for the same.
var fruits = new string[] { "Color", "Price", "Shape ", "Nutrients" };
var fruitDetails = db.Fruits.Where(f => f.FruitId == 5).Select(f => new FruitModel{Id = f.FruitId,Category=f.Category, Color = f.FruitColor, Price=f.FruitPrice, Shape = f.FruitShape, Nutrients = f.FruitNutrients}).FirstOrDefault();
Now I need to populate a list using the results obtained from the Linq query based on the list of fruits.
foreach (var item in fruits )
{
var fruitData = new fruitData ();
fruitData.Category= fruitDetails .Category;
fruitData.Description= ; //This has to be the value of Color if item is color,value of price if item is price and so on...
fruitList.Add(fruitData);
}
So based on what the loop value is corresponding value needs to be populated. I do not want to be using Reflection. Is there an alternate method?
What if you use a switch statement like
switch (item)
{
case "Color":
fruitData.Description = fruitDetails.Color;
break;
case "Price":
fruitData.Description = fruitDetails.Price;
break;
case "Nutrient":
fruitData.Description = fruitDetails.Nutrient;
break;
default:
break;
}
I would suggest adding a property to FruitModel that returns the description based on the instance's Category, and that can use a static Dictionary to map categories to accessor functions:
public class FruitModel {
public int Id;
public string Category;
public string Color;
public double Price;
public string Shape;
public string Nutrients;
static Dictionary<string, Func<FruitModel, string>> catmap = new Dictionary<string, Func<FruitModel, string>> {
{ "Color", fm => fm.Color },
{ "Price", fm => fm.Price.ToString() },
{ "Shape", fm => fm.Shape },
{ "Nutrients", fm => fm.Nutrients },
};
public string Description {
get => catmap[Category](this);
}
public static List<string> FruitDetailCategories {
get => catmap.Keys.ToList();
}
}
You can also create a static property to return the detail categories rather than put the list somewhere else.
(Obviously you could use the switch instead of the Dictionary if preferred in the property body, but it doesn't lend itself to providing the detail categories.)
Now you can build your list easily:
var fruitList = new List<FruitData>();
foreach (var fruit in fruitDetails) {
var fd = new FruitData();
fd.Category = fruit.Category;
fd.Description = fruit.Description;
fruitList.Add(fd);
}

Define list of objects. Get by specific field in object

How can we create a list of objects in C# and acces them by a specific field inside this object?
For example take this object:
class Section
{
public string Name { get; }
public long Size { get; }
public Section(string name, long size)
{
Name = name;
Size = size;
}
}
I would like to create a list of these objects which I can access by Section.Name.
I can create a dictionary like:
private static readonly Dictionary<string, Section> validSections = new Dictionary<string, Section>
{
{ "section-a", new Section("section-a", 1) },
{ "section-b", new Section("section-b", 2) },
{ "section-c", new Section("section-c", 3) },
{ "section-d", new Section("section-d", 4) },
};
But as you see, I have to declare the section name twice, which looks inelegant. Is there a more elegant way?
But as you see, I have to declare the section name twice, which looks
inelegant. Is there a more elegant way?
To avoid repetitve typing you can create dictionary from collection of sections via ToDictionary call:
private static readonly Dictionary<string, Section> validSections = new[] {
new Section("section-a", 1),
new Section("section-b", 2),
new Section("section-c", 3),
new Section("section-d", 4)
}.ToDictionary(s => s.Name);
If this is not time critical then you can use List<Section> list = new ArrayList<Section>(); and store data in it.
Later you can use LINQ to query based on name .where(x=>x.Name=="somename")
First of all your Model class can look like:
class Section
{
public string Name { get; set; }
public long Size { get; set; }
}
You don't need the Name twice so you can just create a list:
private static List<Section> myList = new List<Section>();
myList.add(new Section {Name = "section-a", Size = 1});
// do this for all the sections ...
Then as other answers suggest you can use LINQ:
myList.Single(s => s.Name == "section-a");
Will simply return the single element where the name is "section-a".
Read more about LINQ here: https://msdn.microsoft.com/en-us/library/bb308959.aspx
You could write a function that takes a list of sections and returns the corresponding dictionary. Something like:
public static Dictionary<string, Section> SectionDictionary(List<Section> sections) {
var dict = new Dictionary<string, Section>();
foreach (var section in sections)
dict.Add(section.Name, section);
return dict;
}
You can just access the elements using LINQ:
var list = ...;
var el = list.FirstOrDefault(o => o.Name = nameValue);
Or you can create a (collection) class that implements your own indexer / getter logic. E.g. (pseudocode)
public class MyCollection : Collection<Section>
{
public Section this[string nameValue]
{
get
{
return this.FirstOrDefault(o => o.Name == nameValue);
}
}
}
Then the usage is:
var coll = new MyCollection() ....;
var el = coll["Some name"];

Why isn't my object being updated

I'm doing something wrong because after the loop executed myData still contains objects with blank ids. Why isn't the myData object being updated in the following foreach loop, and how do I fix it?
I thought it could be that I wasn't passing the object by reference, but added a ref keyword and also moved to the main method and I'm still showing the object not being updated.
Additional Information
The user object in the foreach loop is being updated, but the myData list does not reflect the updates I see being applied to the user object.
** Solution **
I was not creating a List but an Enumerable which was pulling the json each time I went through myData in a foreach list. Adding a ToList() fixed my issue.
public class MyData
{
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
int index = 0;
// Does not allow me to up, creates an IEnumerable
//IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
// .Select(x => new MyData()
// {
// ID = x["id"].ToString(),
// Properties = x.OfType<JProperty>()
// .ToDictionary(y => y.Name, y => y.Value.ToString())
// });
//Works allows me to update the resulting list.
IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
.Select(x => new MyData()
{
ID = x["id"].ToString(),
Properties = x.OfType<JProperty>()
.ToDictionary(y => y.Name, y => y.Value.ToString())
}).ToList();
foreach (var user in myData) // Also tried myData.ToList()
{
if (string.IsNullOrEmpty(user.ID))
{
user.ID = index.ToString();
user.Properties["id"] = index.ToString();
}
index++;
}
public class MyData
{
public MyData()
{
this.Properties = new Dictionary<string,string>();
}
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
public static void Main(string[] args)
{
IEnumerable<MyData> myDataList = new List<MyData>();
int index = 0; // Assuming your starting point is 0
foreach (var obj in myDataList)
{
if (obj != null && string.IsNullOrEmpty(obj.ID))
{
obj.ID = index.ToString();
// Checks if the Properties dictionary has the key "id"
if (obj.Properties.ContainsKey("id"))
{
// If it does, then update it
obj.Properties["id"] = obj.ID;
}
else
{
// Else add it to the dictionary
obj.Properties.Add("id", obj.ID);
}
}
index++;
}
I believe the reason why your objects are not updating because it's probably still referring to the memory block before your objects were changed. Perhaps. The easiest way (that I can think of, there are thousands of smarter programmers than me) is to create a new list and have it contain all of your updated objects.
Edit
I updated the code above with the code that I have. I created a method to set a small amount of objects to test:
private static IEnumerable<MyData> GetMyData()
{
return new List<MyData>()
{
new MyData(),
new MyData() {ID = "2"},
new MyData() {ID = "3"},
new MyData()
};
}
I was able to view my changes and then go through a foreach loop to view my changes. If the ID of the object is Null or Empty, then it steps into the if check and adds the current index to the ID as you know.
Now for my question: Which "id" is blank? The "id" in the dictionary or is it the ID of the model? Are all of your (Model).ID blank? As the updated code of yours, if your dictionary doesn't have "id" as a key, it's going to throw an exception saying it doesn't exist so you will need to do a check to make sure it does exist or add it if it doesn't.

Set selected value in dropdown list

How do I set the selected value on a drop down list? Here is what I have so far:
#model Web.Models.PostGraduateModels.PlannedSpecialty
#Html.DropDownList("PlannedSpecialtyID")
//controller
[HttpGet]
public PartialViewResult PlannedSpecialty()
{
// Get Planned Specialty ID
var pgtservice = new PgtService();
PostGraduateModels.PlannedSpecialty plannedSpecialty = pgtservice.GetPlannedSpecialtyId();
// Get Data for Planned Specialty DropDown List from SpecialtyLookup
var pgtServ = new PgtService();
var items = pgtServ.GetPlannedSpecialtyDropDownItems();
ViewBag.PlannedSpecialtyId = items;
return PartialView(plannedSpecialty);
}
// service
public IEnumerable<SelectListItem> GetPlannedSpecialtyDropDownItems ()
{
using (var db = Step3Provider.CreateInstance())
{
var specialtyList = db.GetPlannedSpecialtyDdlItems();
return specialtyList;
}
}
// data access
public IEnumerable<SelectListItem> GetPlannedSpecialtyDdlItems()
{
IEnumerable<Specialty> specialties = this._context.Specialties().GetAll();
var selList = new List<SelectListItem>();
foreach (var item in specialties)
{
var tempps = new SelectListItem()
{
Text = item.Description,
Value = item.Id.ToString()
};
selList.Add(tempps);
}
return selList;
}
I would recommend you to avoid using ViewBag/ViewData/ Weekly typed code. Use strongly typed code and it makes it more readable. Do not use the Magic strings/ Magic variables. I would add a collection property to your ViewModel to hold the SelectList items and another property to hold the selected item value.
public class PlannedSpecialty
{
public IEnumerable<SelectListItem> SpecialtyItems { set;get;}
public int SelectedSpeciality { set;get;}
//Other Properties
}
and in your Get action, If you want to set some Item as selected,
public PartialViewResult PlannedSpecialty()
{
var pgtServ = new PgtService();
var vm=new PlannedSpecialty();
vm.SpecialtyItems = pgtServ.GetPlannedSpecialtyDropDownItems();
//just hard coding for demo. you may get the value from some source.
vm.SelectedSpeciality=25;// here you are setting the selected value.
return View(vm);
}
Now in the View, use the Html.DropDownListFor helper method
#Html.DropDownListFor(x=>x.SelectedSpeciality,Model.SpecialtyItems,"select one ")
Use the selected property of the SelectListItem class:
selList.Selected = true;

Categories