How to append items to a bound list? - c#

I have the following models:
class Order
{
public List<Product> Products { get; set; }
}
class Products
{
public int Price { get; set; }
}
In my razor page I want to loop over all products and to be able to add them to my order, like this:
int i = 0;
foreach (Product p in AllProducts)
{
<input asp-for="order.Products[i].Price">
i++;
}
This works fine when creating a new order (when the list pf products is empty), but when I try to edit the order, and maybe add new products or edit the existing ones, I'm getting an Index was out of range. exception.
Obviously because there are more products in AllProducts than there are in the order's Products list.
Is there a way to overcome this?

We can do by update code. I think resolved issue. Problem was in foreach loop.
int i = 0;
foreach (Product p in AllProducts)
{
<input asp-for="AllProducts[i].Price">
i++;
}
Still, you are facing the issue please share razor view.

How about just looping after the last index of your current orders:
int i = order.Products.Count();
foreach (Product p in AllProducts)
{
<input asp-for="order.Products[i].Price">
i++;
}

While getting the order from the DB for editing, you need to fetch the associated products as well. You can use Include to fetch them. See here for more details on that. Once you get the products, then you can use the products to list and also use the AllProducts to enable the use to add the products which were not in the list

Try the following modification in Edit order page:
#for (int i = 0; i < Model.Order.Products.Count(); i++)
{
<input asp-for="Order.Products[i].Price">
}

Related

How to filter double elements in an object C#

Well I have a list which is called employeeList. In the emoloyee Liste there are stored employees with some attributes like id, lastname ...
One of the attributes is Department. Now I want to create Radio Buttons with the Department. As there are more employees per department one department can appear several times but this I'd like to avoid. This is what I already got:
for (int i = 0; i < employeeList.Count(); i++)
{
panDepartments.Children.Add(new RadioButton() { Content = employeeList.ElementAt(i).Department.Distinct()});
}
Just filter the list before you iterate over it. One possibility would be LINQ (i.e. Distinct()) or just do the filtering yourself.
I think you can try something like this.
//First of all we need to get unique departments.
var departments = employeeList.Select(e => e.Department).Distinct();
//And after that we can create radio buttons and add them as children elements.
foreach(var dep in departments)
{
panDepartments.Children.Add(new RadioButton() { Content = dep });
}
//foreach loop can be replaced something like this if "panDepartments.Children"
//supports "AddRange" method
var radioBtns = departments.Select(d => new RadioButton() { Content = dep });
panDepartments.Children.AddRange(radioBtns);

Creating ListView from a List of class objects returns same object instead of all C# UWP

I am attempting to list the List's items but I get repeatedly displayed the first row of the List. The List should contain three different product rows. Instead, ListView shows the same, first row three times.
I create list like this:
List<ProductsNumber> ProductsNumberList = new List<ProductsNumber>();
ProductsNumber _ProductsNumber = new ProductsNumber();
for (int i= 0; i <= otherlist.Count - 1; i++)
{
_ProductsNumber.ProdId = otherlist[i].ProdName.ToString();
_ProductsNumber.ProductsNumber = (DB_ProductList.Where(Product => Product.ProdId == otherlist[i].ProdName)).Count();
ProductsNumberList.Add(_ProductsNumber);
}
//listView
listBox.ItemsSource = ProductsNumberList;//Binding data to LISTBOX
And here is the class used to populate List:
public class ProductsNumber
{
public string ProdId { get; set; }
public int ProductsNumber { get; set; }
}
If you are interested:
otherlist
works just fine when I list it in listview.
DB_ProductList is defined like this:
ReadAllProductsList dbproduct = new ReadAllProductsList();
DB_ProductList = dbdproduct.GetAllProducts();
List<Product> ProductList = new List<Product>();
ProductList = DB_ProductList.ToList();
and it works well too.
Anyway, I get correct ProductNumber in ListView. It's the ProdId that gives me problems. I get indeed correct number of iterations in ListView, but they all are the same. ListView should list all Products, and not repeat the same one.
Any clue?
I am guessing that when populating List the same record is inserted three times. But why?
Oh, I solved the mystery.
Simply, moved the
ProductsNumber _ProductsNumber = new ProductsNumber();
line inside the for
loop and it works fine now.
Silly me.
Can you try write "ProductsNumber _ProductsNumber = new ProductsNumber();" into the loop?

Dynamic list of dropdownlists

I'm working on my first MVC project and I wanted to see if there's a better way to do this. I'm pretty sure there is.
I'm building an application for audits. Each audit has a list of questions, and each question has a list of options to select from. The questions and options can change. So, I have to dynamically build the table of questions and the dropdowns with the question's options.
Here's how I'm creating the SelectLists in the controller
foreach (var r in employeeAuditData.Audit.AuditResults)
{
ViewData["Result" + r.AuditQuestionID] =
new SelectList(r.AuditQuestion.QuestionOptions, "QuestionOptionID", "OptionText", r.QuestionOption);
}
And here's the code for my view
foreach (var r in Model.Audit.AuditResults.OrderBy(r => r.AuditQuestion.Ordinal).ToList())
{
<tr>
<td>#r.AuditQuestion.QuestionText</td>
<td>#Html.DropDownList("Result" + r.AuditQuestionID, "(Select)")</td>
</tr>
}
This works but using concatenation for the ViewData key seems like a funky way to do this. Is there a better way?
How about making a ViewModel?
class AuditResultSelectList
{
int QuestionId { get; set;}
SelectList QuestionOptions { get; set;}
}
Then in your controller:
List<AuditResultSelectList> list = new List<AuditResultSelectList>();
foreach (var r in employeeAuditData.Audit.AuditResults)
{
AuditResultSelectList a = new AuditResultSelectList()
{
QuestionId = r.AuditQuestionID,
QuestionOptions = new SelectList(r.AuditQuestion.QuestionOptions, "QuestionOptionID", "OptionText", r.QuestionOption)
}
list.Add(a);
}
ViewData["QuestionSelectLists"] = list;
Then your view can pull the list out using:
var x = (List<AuditResultSelectList>) ViewData["QuestionSelectLists"];

Show selected items in a multi-select list box

I have tried various ways to get this to work. I think maybe I have something missing in my model or controller, so I'm posting all three parts.
I have data in a database that shows some advising topics chosen by an advisor in a previous appointment. When the advisor calls up that appointment, the app should display a list of all possible topics with the ones previously chosen highlighted. Everything works except that last bit.
I know I'm retrieving the right information because I can display the selected items separately. I just can't get them to show up selected. Here's the code. I'm cutting out irrelevant parts.
public class AppointmentModel
{ ...
public string AdvisingTopicId { get; set; }
public List<SelectListItem> AdvisingIdList { get; set; }
public SelectList AdvisingTopicNames { get; set; }
}
public class HomeController : AdvisorBaseController
{ ...
var topicCodes = appointment.advising_topic.ToList();
var advisingTopics = new SelectList((from t in topicCodes
select t.name).ToList(), "name");
var topicsList = (from t in db.advising_topic
select new SelectListItem
{
Selected = false,
Text = t.name,
Value = SqlFunctions.StringConvert((double)t.advising_topic_id).Trim()
}).ToList();
foreach (var topicCode in topicCodes)
{
var selTopic = topicsList.Find(x => x.Value == topicCode.advising_topic_id.ToString());
if (selTopic != null)
{
selTopic.Selected = true;
}
} ...
var appointmentModel = new AppointmentModel
{ ...
AdvisingTopicNames = advisingTopics,
AdvisingIdList = topicsList,
};
and then the view
#model AcademicAdvising.Models.AppointmentModel
<h3>Advising Topics</h3>
<ul>
#foreach (var item in Model.AdvisingTopicNames)
{
<li>#Html.DisplayFor(x => item)</li>
}
</ul>
#Html.ListBoxFor(m=>m.AdvisingIdList, new SelectList(Model.AdvisingTopicNames, "Value", "Text", Model.AdvisingTopicNames.SelectedValue))
Note that the foreach correctly displays the selected items. That's just for testing and will be pulled out. the ListBoxFor is where I'm struggling. What I have here doesn't work (shows the full list with nothing highlighted). And that's the bit where I have tried various approaches, with all fails.
It looks like you may have accidentely went a level too deep. You already have a select list which is all the listboxfor function wants.
#Html.ListBoxFor(m=>m.AdvisingIdList, Model.AdvisingTopicNames)
But honestly looking at how you are defining your lists I think what you really want might be
#Html.ListBoxFor(m=>m.AdvisingIdList, Model.AdvisingIdList)

How can I get all element values from Request.Form without specifying exactly which one with .GetValues("ElementIdName")

Currently using the below code to create a string array (elements) that contains all
string values from Request.Form.GetValues("ElementIdName"), the problem is that in order for
this to work all my dropdown lists in my View have to have the same element ID name which
I don't want them to for obvious reasons. So I am wondering if there's any way for me to get
all the string values from Request.Form without explicitly specifying the element name. Ideally I would want to get all dropdown list values only, I am not too hot in C# but isn't there some way to get all element ID's starting with say "List" + "**", so I could name my lists List1, List2, List3 etc.
Thanks..
[HttpPost]
public ActionResult OrderProcessor()
{
string[] elements;
elements = Request.Form.GetValues("List");
int[] pidarray = new int[elements.Length];
//Convert all string values in elements into int and assign to pidarray
for (int x = 0; x < elements.Length; x++)
{
pidarray[x] = Convert.ToInt32(elements[x].ToString());
}
//This is the other alternative, painful way which I don't want use.
//int id1 = int.Parse(Request.Form["List1"]);
//int id2 = int.Parse(Request.Form["List2"]);
//List<int> pidlist = new List<int>();
//pidlist.Add(id1);
//pidlist.Add(id2);
var order = new Order();
foreach (var productId in pidarray)
{
var orderdetails = new OrderDetail();
orderdetails.ProductID = productId;
order.OrderDetails.Add(orderdetails);
order.OrderDate = DateTime.Now;
}
context.Orders.AddObject(order);
context.SaveChanges();
return View(order);
}
You can get all keys in the Request.Form and then compare and get your desired values.
Your method body will look like this: -
List<int> listValues = new List<int>();
foreach (string key in Request.Form.AllKeys)
{
if (key.StartsWith("List"))
{
listValues.Add(Convert.ToInt32(Request.Form[key]));
}
}
Waqas Raja's answer with some LINQ lambda fun:
List<int> listValues = new List<int>();
Request.Form.AllKeys
.Where(n => n.StartsWith("List"))
.ToList()
.ForEach(x => listValues.Add(int.Parse(Request.Form[x])));
Here is a way to do it without adding an ID to the form elements.
<form method="post">
...
<select name="List">
<option value="1">Test1</option>
<option value="2">Test2</option>
</select>
<select name="List">
<option value="3">Test3</option>
<option value="4">Test4</option>
</select>
...
</form>
public ActionResult OrderProcessor()
{
string[] ids = Request.Form.GetValues("List");
}
Then ids will contain all the selected option values from the select lists. Also, you could go down the Model Binder route like so:
public class OrderModel
{
public string[] List { get; set; }
}
public ActionResult OrderProcessor(OrderModel model)
{
string[] ids = model.List;
}
Hope this helps.
Request.Form is a NameValueCollection. In NameValueCollection you can find the GetAllValues() method.
By the way the LINQ method also works.

Categories