Populating C# listview with context menu item - c#

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

Related

datagridview in winform, columncombobox value change

I am designing a winform in which I have a datagridview with predefined columns, the first column is a combobox and rest 3 columns are textboxes.
I am not binding datagridview to any datasource since the user is going to fill the last column "Qty", all I want to achieve is, when user clicks on the combobox it should show 3 columns from the database table (item code, item name and uom) and when user select any particular "item code" corresponding "item name" and "uom" should be displayed in second column and third column of the datagridview. Likewise the user should be able to enter as many row as he require. After data entry the data will be saved in a table named "purchase requisition".
I have not done any coding so far and have designed only the form.
See if the following will provide base code to roll with. There are several classes to mock up data and a extension method which should be move to own files.
DataGridView was not configured in the designer, just in code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace UnboundDataGridViewComboBox
{
public partial class Form1 : Form
{
private ComboBox _cbo;
private string _comboColumnName = "ItemCodeColumn";
private List<Item> _items => Mocked.Items;
public Form1()
{
InitializeComponent();
Shown += OnShown;
}
private void OnShown(object sender, EventArgs e)
{
var column1 = new DataGridViewComboBoxColumn
{
DataSource = _items.Select(x => x.ItemCode).ToArray(),
DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing,
Name = _comboColumnName,
HeaderText = "Item Code",
SortMode = DataGridViewColumnSortMode.NotSortable
};
var column2 = new DataGridViewTextBoxColumn
{
Name = "ItemNameColumn",
HeaderText = "Item Name"
};
var column3 = new DataGridViewTextBoxColumn
{
Name = "UomColumn",
HeaderText = "UOM"
};
var column4 = new DataGridViewTextBoxColumn
{
Name = "QuanityColumn",
HeaderText = "Quanity"
};
ItemsDataGridView.Columns.AddRange(column1, column2, column3, column4);
ItemsDataGridView.EditingControlShowing += DataGridView1OnEditingControlShowing;
}
private void DataGridView1OnEditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (!ItemsDataGridView.CurrentCell.IsComboBoxCell()) return;
if (ItemsDataGridView.Columns[ItemsDataGridView.CurrentCell.ColumnIndex].Name != _comboColumnName) return;
_cbo = e.Control as ComboBox;
_cbo.SelectedIndexChanged -= ItemCodeColumnComboSelectionChanged;
_cbo.SelectedIndexChanged += ItemCodeColumnComboSelectionChanged;
}
private void ItemCodeColumnComboSelectionChanged(object sender, EventArgs e)
{
DataGridViewComboBoxEditingControl control = sender as DataGridViewComboBoxEditingControl;
Item item = _items.FirstOrDefault(x => x.ItemCode == control.EditingControlFormattedValue.ToString());
if (item == null)
{
return;
}
ItemsDataGridView.CurrentRow.Cells[1].Value = item.Name;
ItemsDataGridView.CurrentRow.Cells[2].Value = item.UOM;
}
}
#region Place classes into their own files
public static class Extensions
{
public static bool IsComboBoxCell(this DataGridViewCell sender)
=> sender.EditType != null &&
sender.EditType == typeof(DataGridViewComboBoxEditingControl);
}
// represents a table in a database
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string ItemCode { get; set; }
public string UOM { get; set; }
public override string ToString() => ItemCode;
}
class Mocked
{
// simulate data from database
public static List<Item> Items => new List<Item>()
{
new Item() {Id = 1,Name = "P1", ItemCode = "A100", UOM = "Q1"},
new Item() {Id = 2,Name = "P2", ItemCode = "A200", UOM = "W1"},
new Item() {Id = 3,Name = "P3", ItemCode = "A300", UOM = "B1"},
new Item() {Id = 4,Name = "P4", ItemCode = "A400", UOM = "H1"}
};
}
#endregion
}

Pass object from DB to next page after listbox selection

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

listBox filled with objects

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

Issue on Rendering List in Grid in C#

I am trying to render a simple List into a Grid like
var sr = new BindingSource();
sr.DataSource = str;
dataGridView1.DataSource = sr;
I am not getting any error but not able to display the list in Grid. Here is the entire code
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Enum
{
public enum Sex {Male, Female, Other };
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
List<Sex> str = new List<Sex>();
str.Add(Sex.Female);
str.Add(Sex.Male);
var sr = new BindingSource();
sr.DataSource = str;
dataGridView1.DataSource = sr;
}
}
}
DataGridView cannot bind to a list of primitive values (like int, decimal, DateTime, enum, string etc.) because it requires a list containing objects with properties.
The easiest way is to use LINQ projection to an anonymous type with single property like this (BindingSource is not needed at all):
private void button1_Click(object sender, EventArgs e)
{
List<Sex> str = new List<Sex>();
str.Add(Sex.Female);
str.Add(Sex.Male);
dataGridView1.DataSource = str.Select(value => new { Sex = value }).ToList();
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class Person
{
public string Name { get; set; }
public string Lastname { get; set; }
public Sex Sex { get; set; }
}
public enum Sex { Male, Female, Other };
private void button1_Click(object sender, EventArgs e)
{
BindingList<Person> persons = new BindingList<Person>();
persons.Add(new Person() { Name = "Joe", Lastname = "Doe" , Sex = Sex.Male});
persons.Add(new Person() { Name = "Nancy", Lastname = "Foo" , Sex = Sex.Female});
dataGridView1.DataSource = persons;
}
}
I don't think you can bind an enum to GridView. This is what I could get working
public class Person
{
public Sex Gender { get; set; }
}
You need to use BindingList as list does not implement IBindingList
var list = new List<Person>()
{
new Person { Gender = Sex.Male, },
new Person { Gender = Sex.Female, },
};
var bindingList = new BindingList<Person>(list);
var source = new BindingSource(bindingList, null);
dataGridView1.DataSource = source;

Error with Employee class creation in C#

I have written this program in C# for an assignment I have due tonight. What I have to do is create a class named "Employee" have have the information display on a List Box. I believe that I have everything together, and I am not showing any syntax errors, but when I attempt to run the program, nothing happens. Do you think you can help me find out why its not working? All that appears is a blank list box. Here is my code on my Form1.cs:
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 Adam_Zeidan___IS_204___HW10CH9_4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listBox1.Items.Add("Name\t\tID Number\tDepartment\tPosition");
Employee emp1 = emp1 = new Employee();
emp1.Name = "Susan Meyers";
emp1.IdNumber = 47899;
emp1.Department = "Accounting";
emp1.Position = "Vice President";
listBox1.Items.Add(emp1.Name + "\t" + emp1.IdNumber + "\t\t" + emp1.Department + "\t" + emp1.Position);
Employee emp2 = emp2 = new Employee();
emp2.Name = "Mark Jones";
emp2.IdNumber = 39119;
emp2.Department = "IT";
emp2.Position = "Programmer";
listBox1.Items.Add(emp2.Name + "\t" + emp2.IdNumber + "\t\t" + emp2.Department + "\t" + emp2.Position);
Employee emp3 = emp3 = new Employee();
emp3.Name = "Joy Rogers";
emp3.IdNumber = 81774;
emp3.Department = "Manufacturing";
emp3.Position = "Engineer";
listBox1.Items.Add(emp3.Name + "\t" + emp3.IdNumber + "\t\t" + emp3.Department + "\t" + emp3.Position);
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
Now this is the Employee.cs code that I used to create the class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Adam_Zeidan___IS_204___HW10CH9_4
{
class Employee
{
private string _name;
private int _idNumber;
private string _department;
private string _position;
public Employee()
{
_name = "";
_idNumber = 0;
_department = "";
_position = "";
}
public Employee(string name, int idNumber)
{
_name = name;
_idNumber = idNumber;
_department = "";
_position = "";
}
public Employee(string name, int idNumber, string department, string position)
{
_name = name;
_idNumber = idNumber;
_department = department;
_position = position;
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int IdNumber
{
get
{
return _idNumber;
}
set
{
_idNumber = value;
}
}
public string Department
{
get
{
return _department;
}
set
{
_department = value;
}
}
public string Position
{
get
{
return _position;
}
set
{
_position = value;
}
}
}
Do you think you can help me find out why its not working?
Change the following lines
Employee emp1 = emp1 = new Employee();
Employee emp2 = emp2 = new Employee();
Employee emp3 = emp3 = new Employee();
to
Employee emp1 = new Employee();
Employee emp2 = new Employee();
Employee emp3 = new Employee();
I have tried the given snippet; that works fine for me, please check the properties of the ListBox for it's visibility and also make sure that the Form1_Load event is firing. I have a suggestion to simplify your code by overriding .ToString() in the class in the following way:
public override string ToString()
{
return this.Name + "\t" + this.IdNumber + "\t\t" + this.Department + "\t" + this.Position;
}
So that the code in the Form1_Load will be as like the following:
Employee emp1 = new Employee();
emp1.Name = "Susan Meyers";
emp1.IdNumber = 47899;
emp1.Department = "Accounting";
emp1.Position = "Vice President";
listBox1.Items.Add(emp1.ToString());
Employee emp2 = new Employee();
//init emp2 here
listBox1.Items.Add(emp2.ToString());
Employee emp3 = emp3 = new Employee();
//init emp3 here
listBox1.Items.Add(emp3.ToString());

Categories

Resources