I have a listbox populated by products stored in an SQLite DB. The listbox is populated like so:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string navigatedFrom;
base.OnNavigatedTo(e);
navigatedFrom = (string)e.Parameter;
if (navigatedFrom == "main")
{
var products = new ObservableCollection<Product>(data.GetProducts().ToList());
foreach (var product in products)
{
ListBox.Items.Add("Product Name: " + product.ProductName + " Price: " + product.Price + " Quantity: " + product.Quantity);
}
}
else
{
}
}
and the listbox selection is handled like this:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var product = ListBox.SelectedItem as Product;
if (product != null)
{
Frame.Navigate(typeof(DetailsPage), product.Id);
}
ListBox.SelectedIndex = -1;
}
When a product is selected from the listbox the app should navigate to the details page which shows all of the details from the selected product object. My problem occurs when I select a product from the list, the product object is always null. How can I make sure the product object is populated in the correct format with the correct information?
change this:
foreach (var product in products)
{
ListBox.Items.Add("Product Name: " + product.ProductName + " Price: " + product.Price + " Quantity: " + product.Quantity);
}
to
foreach (var product in products)
{
ListBox.Items.Add(product);
}
example Product class:
public class Product
{
public string ProductName { get; private set; }
public string Price { get; private set; }
public string Quantity { get; private set; }
public override string ToString()
{
return $"Product Name: {this.ProductName} Price: {this.Price} Quantity: {this.Quantity}";
}
}
Related
With these models:
public class Course
{
public Guid Id { get; set; }
public string Title { get; set; }
public IList<CourseEvent> CourseEvents { get; set; }
}
public class CourseEvent
{
public Guid Id { get; set; }
public Guid CourseId { get; set; }
public DateTime StartDate { get; set; }
}
...and this method:
private void WritePropertyNames(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
Console.WriteLine(item.Name + " => " + item.GetValue(obj, null));
}
}
...I can get the property names and values on any object provided:
var course = new Course { Title = "My course", CourseEvents = new List<CourseEvent>() { new() { StartDate = DateTime.Today }, new() { StartDate = DateTime.Today.AddDays(-1) } } };
WritePropertyNames(course);
But how do I get the related CourseEvents property names and values too? I've tried this, but that's not right:
foreach (var item2 in obj.GetType().GetProperty("CourseEvents").GetType().GetProperties())
{
Console.WriteLine(item2.Name + " => " + item2.GetValue(obj, null));
}
It might be ugly and not optimal and won't work for all the cases (quickly wrote it just to demonstrate the idea)
So you could check if property is Generic by item.PropertyType.IsGenericType, you could also check if it type implements IEnumerable typeof(IEnumerable).IsAssignableFrom(item.PropertyType). Then you could get the underlying type using item.PropertyType.GenericTypeArguments[0]. Then it basically becomes your logic that you have - you iterating over objects and getting props as you already have
private static void WritePropertyNames(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
if(item.PropertyType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(item.PropertyType))
{
var innerProps = item.PropertyType.GenericTypeArguments[0].GetProperties();
foreach(var innerItem in item.GetValue(obj, null) as IEnumerable)
{
foreach(var innerProp in innerProps)
{
Console.WriteLine(item.Name + " => " + innerProp.Name + " => " + innerProp.GetValue(innerItem, null));
}
}
}
else
{
Console.WriteLine(item.Name + " => " + item.GetValue(obj, null));
}
}
}
So I have a class called Person. Each Person can have a Name, Age and Email. And I have about 50 Person objects stored in a list called PersonList. Which I defined like this:
List<Person> PersonList = new List<Person>();
The array looks something like this:
PersonList = {
{
name: 'John',
age: 30,
email: 'John#email.com'
},
{
name: 'Bill',
age: 55,
email: 'Bill#email.com'
}
}
I then loop through this and add each of their Name in to a ListBox:
foreach (var Person in PersonList)
{
ListBox.Items.Add(Person.Name);
}
Please note: All names are unique.
What I want to do now, is that when I select a name in the ListBox, I want their Name, Age and Email to be displayed in a label called Label1. Currently, I accomplish this by looping through the PersonList and checking for a name that matches the selected ListBox item's text.
private void ListBox_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (var Person in PersonList)
{
if (Person.Name == ListBox.SelectedItem.ToString())
{
Label1.Text = "Name: " + Person.Name + Environment.NewLine +
"Age: " + Person.Age + Environment.NewLine +
"Email: " + Person.Email;
}
}
}
It works, but is this the correct way of doing it? I feel like constantly looping through the PersonList to compare names could be bad for the performance. What if PersonList contained thousands of objects?
I also wonder if there is a better way to insert all the Person.Name in to the ListBox? Or is looping the way to go? I know about AddRange, but can I do that on just the Person.Name somehow? Note: I only want to add their names in to the ListBox.
What would you do?
You can fill the listbox directly with the list, and the selection of the item can be done in 3 ways, see the code:
public class Pessoa
{
public string Nome { get; set; }
public string Email { get; set; }
public override string ToString()
{
return this.Nome.ToString();
}
}
List<Pessoa> lista = new List<Pessoa>();
private void Form1_Load(object sender, EventArgs e)
{
lista.Add(new Pessoa() { Nome = "Rovann1", Email = "Teste1#Teste.com" });
lista.Add(new Pessoa() { Nome = "Rovann2", Email = "Teste2#Teste.com" });
lista.Add(new Pessoa() { Nome = "Rovann3", Email = "Teste3#Teste.com" });
listBox1.DisplayMember = "Nome";
listBox1.DataSource = lista;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
label1.Text = "Select one item";
//1
if (listBox1.SelectedItem != null)
{
label1.Text = ((Pessoa)listBox1.SelectedItem).Email;
}
//2
Pessoa p = lista.Find(x => x.Nome == listBox1.SelectedItem.ToString());
if (p != null)
label1.Text = p.Email;
//3
if (listBox1.SelectedIndex >= 0)
label1.Text = lista[listBox1.SelectedIndex].Email;
}
I have Program.cs class like this
var products = new List<object>();
var f1 = new Fruit("Apple", 25.34, 5);
products.Add(f1);
foreach (var item in products)
{
Console.WriteLine(item);
}
and this is my Fruit.cs class
public Fruit(string name, double weight, int quantity)
{
Name = name;
Weight = weight;
Quantity = quantity;
}
public string Name { get; set; }
public double Weight { get; set; }
public int Quantity { get; set; }
when i run this program this is written on the screen
ConsoleApplication1.Fruit
my question is how to print the values (Apple,25.34,5) which I stored in my products list?
Any help is appreciated. Thanks.
Override the ToString() method:
public override ToString()
{
return this.Name + "," + this.Weight + "," + this.Quantity
}
You could try something like this:
foreach (var item in products)
{
Console.WriteLine(String.Format("Name: {0}, Weight: {1}, Quantity: {2}",
((Fruit)item).Name,
((Fruit)item).Weight,
((Fruit)item).Quantity));
}
or you could override the ToString method of Fruits class:
public class Fruit
{
public string Name { get; set; }
public double Weight { get; set; }
public int Quantity { get; set; }
public Fruit(string name, double weight, int quantity)
{
Name = name;
Weight = weight;
Quantity = quantity;
}
public override string ToString()
{
return String.Format("Name: {0}, Weight: {1}, Quantity: {2}", Name, Weight, Quantity);
}
}
and live your foreach statement as it is:
foreach (var item in products)
{
Console.WriteLine(item);
}
The reason why you get ConsoleApplication1.Fruits is because the default implemenation of the ToString method, that is called under the hood in the Console.WriteLine above, returns the full name of type of the object. Overriding this method, you can make it to return whatever your want.
you can do like this
foreach (var item in products)
{
Console.WriteLine("Name: {0}, Weight: {1}, Quantity: {2}",
((Fruit)item).Name,
((Fruit)item).Weight,
((Fruit)item).Quantity);
}
or you can override your ToString method in Fruit Class and change it like this
public override string ToString()
{
return Name+":"+Weight+":"+Quantity;
}
change
var products = new List<object>();
to
var products = new List<Fruits>();
so that you can write like this so will display like a table:
var products = new List<object>();
var f1 = new Fruits("Apple", 25.34, 5);
var f2 = new Fruits("Orange", 18.19, 3);
products.Add(f1);
products.Add(f2);
String ss = "Item\t\tWeight\t\tQty\n";
for (int i = 0; i < 60; i++) ss += "-";
Console.WriteLine(ss);
foreach (var item in products)
{
Console.WriteLine(item.Name.ToString() + "\t\t" + item.Weight.ToString() + "\t\t" + item.Quantity.ToString());
}
Just write: Console.WriteLine(item.Name, item.Weight, item.Quantity);
More information:
Each item in the products list is of type Fruit. So if you want to print the right information, you need to access the properties (Name, Weight, Quantity) of the Fruit (item) object.
foreach (var item in products)
{
Console.WriteLine((Fruit)item.Name, (Fruit)item.Weight, (Fruit)item.Quantity);
}
I was wondering how I properly can populate the labels in my form with the information from the selected preset item found in the 'right-click' context menu? I'm currently populating the context menu with the 'name' of each class 'product'. I'd like to then fill in the labels corresponding to the item selected by the users right-click menu. The context menu items will change dynamically as items get added to the list.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace rcMenu
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Product newProductA = new Product();
newProductA.Name = "Ice Cream";
newProductA.Category = "Dessert";
newProductA.Price = "Free";
productList.Add(newProductA);
Product newProductB = new Product();
newProductB.Name = "Cherries";
newProductB.Category = "Produce";
newProductB.Price = "$10.00";
productList.Add(newProductB);
Product newProductC = new Product();
newProductC.Name = "Soda";
newProductC.Category = "Beverage";
newProductC.Price = "$1.99";
productList.Add(newProductC);
}
public static List<Product> productList = new List<Product>();
public class Product
{
public String Name { get; set; }
public String Category { get; set; }
public String Price { get; set; }
}
private void SelectedPreset(object sender, EventArgs e)
{
label1.Text = "Product Name: " + "SELECTED";
label2.Text = "Product Category: " + "SELECTED";
label3.Text = "Product Price: " + "SELECTED";
}
private void contextMenuStrip1_Opened(object sender, EventArgs e)
{
(contextMenuStrip1.Items[0] as ToolStripMenuItem).DropDownItems.Clear();
foreach (var p in productList)
{
var itemName = p.Name;
(contextMenuStrip1.Items[0] as ToolStripMenuItem).DropDownItems.Add(itemName, null, SelectedPreset);
}
}
}
}
First subscribe to the Opening event and place the code like this:
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
if(contextMenuStrip1.Items.Count > 0)
contextMenuStrip1.Items.Clear();
foreach (var p in productList)
{
var itemName = p.Name;
contextMenuStrip1.Items.Add(itemName);
}
e.Cancel = false;
}
Next subscribe to the ItemClicked event and place the code like this:
private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
Product p = productList.Find(i => i.Name == e.ClickedItem.Text);
//just in case its null...
if(p != null)
{
label1.Text = "Product Name: " + p.Name;
label2.Text = "Product Category: " + p.Category;
label3.Text = "Product Price: " + p.Price;
}
}
Try this!
private void SelectedPreset(object sender, EventArgs e)
{
var p = productList.Where(x => x.Name == (sender as ToolStripMenuItem).Text).Single();
label2.Text = "Product Category: " + (sender as ToolStripMenuItem).Text;
label3.Text = "Product Price: " + p.Price;
}
you must polish up a bit add the proper validation
I have a winforms app that takes in user input, and adds it to a list. This list is then displayed in a listbox.
My issue is that I want the listbox to display the individual items once only on one line.
Currently it would look like this:
Product Price Quantity
Bread 1.20 1
Bread 2.40 2
Bread 3.60 3
Eggs 1.50 1
Eggs 3.00 2
I would like it to display:
Product Price Quantity
Bread 3.60 3
Eggs 3.00 2
Is it possible to achieve this?
private void btnAdd_Click(object sender, EventArgs e)
{
lbBasket.DisplayMember = "ProductName";
try
{
string name = textBoxProduct.Text.ToString();
decimal price = Convert.ToDecimal(textBoxPrice.Text);
int quantity = Convert.ToInt32(textBoxQuantity.Text);
if (string.IsNullOrWhiteSpace(textBoxQuantity.Text))
{
shoppingBasket.AddProduct(name, price);
lbBasket.Items.Add(textBoxProduct.Text);
lbPrice.Items.Add(shoppingBasket.BasketTotal);
lbQuantity.Items.Add(shoppingBasket.NumberOfTotalQuantities);
}
else
{
shoppingBasket.AddProduct(name, price, quantity);
lbPrice.Items.Add(shoppingBasket.BasketTotal);
lbQuantity.Items.Add(shoppingBasket.NumberOfTotalQuantities);
foreach (OrderItem item in shoppingBasket)
{
if (item.ProductName == name)
{
lbBasket.Items.Add(item.ProductName);
}
}
}
}
Here is a full example showing you how you could use a single ListBox.
using System;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
lbBasket.Items.Add(new Basket("Name 1", (decimal) 1.00, 1));
lbBasket.Items.Add(new Basket("Name 2", (decimal) 2.00, 2));
}
private void btnAdd_Click(object sender, EventArgs e)
{
var newItem = new Basket(txtName.Text, Convert.ToDecimal(txtPrice.Text), Convert.ToInt32(txtQuantity.Text));
var existingItem =
lbBasket.Items.Cast<Basket>()
.FirstOrDefault(li => li.Name.Equals(newItem.Name, StringComparison.OrdinalIgnoreCase));
// There is something there
if (existingItem != null)
{
// You already have the best one
if (existingItem.Price > newItem.Price)
{
// Do nothing
return;
}
// Price is the same
if (existingItem.Price == newItem.Price)
{
lbBasket.Items.Remove(existingItem);
newItem.Quantity += existingItem.Quantity;
lbBasket.Items.Add(newItem);
}
// Remove the old item and add the new one
else if (existingItem.Price < newItem.Price)
{
lbBasket.Items.Remove(existingItem);
lbBasket.Items.Add(newItem);
}
}
else
{
lbBasket.Items.Add(newItem);
}
}
}
public class Basket
{
public string Name { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public Basket(string name, decimal price, int quantity)
{
Name = name;
Price = price;
Quantity = quantity;
}
public override string ToString()
{
return Name + " £" + Price + " " + Quantity;
}
}
}
When you don't specify a DisplayMember then ToString is called, so I have overridden than in the Basket class to display how you might like it displayed. Edit it for your own needs, but this has the basic log in that you need and should help you on your way. If you have any questions feel free to ask... :)
The logic is that if the name already exists then it will check the price, if the price is the same in the new item it will check the quantity, if the quantity is higher it will update. If the price is higher it will update. In all other cases, no update will be made.
Just add code similar to follows:
foreach(listboxitem itm in lbBasket)
{
if(itm.toString()!=textBoxProduct.Text)
{
lbBasket.Items.Add(textBoxProduct.Text);
}
}
Likewise keep loop for all the 3 listboxes you are having.
You can do it with LINQ :
class Program
{
static void Main(string[] args)
{
List<ShoppingBasket> bag = new List<ShoppingBasket>();
bag.Add(new ShoppingBasket("Bread", 1.20M, 1));
bag.Add(new ShoppingBasket("Bread", 2.40M, 2));
bag.Add(new ShoppingBasket("Bread", 3.60M, 3));
bag.Add(new ShoppingBasket("Eggs", 1.50M, 1));
bag.Add(new ShoppingBasket("Eggs", 3.000M, 2));
var result = from x in bag
group x by x.Product into g
select new ShoppingBasket(g.Key, g.Max(x => x.Price),
g.Max(x => x.Quantity));
}
}
public class ShoppingBasket
{
public string Product { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public ShoppingBasket(string product, decimal price, int quantity)
{
this.Product = product;
this.Price = price;
this.Quantity = quantity;
}
}