Update a List<t> object and his properties - c#

I have a list MemoryClienti with items based on the ClienteModel class.
The method i use to add a new item to MemoryClienti is:
public bool CreateCliente(ClienteModel model)
{
bool empty = !MemoryClienti.Any();
if (empty)
{
ClienteModel clienteModel = new ClienteModel();
clienteModel.Cognome = model.Cognome;
clienteModel.Nome = model.Nome;
clienteModel.Indirizzo = model.Indirizzo;
clienteModel.IDCliente = StartID;
MemoryClienti.Add(clienteModel);
MessageBox.Show("Cliente aggiunto correttamente.");
}
else
{
int maxID = MemoryClienti.Count;
ClienteModel clienteModel = new ClienteModel();
clienteModel.Cognome = model.Cognome;
clienteModel.Nome = model.Nome;
clienteModel.Indirizzo = model.Indirizzo;
clienteModel.IDCliente = maxID;
MemoryClienti.Add(clienteModel);
MessageBox.Show("Cliente aggiunto correttamente.");
}
return true;
This method makes me able to add a new item, count for the number of items in the list, and set the new item's id as the result of the count, so it happpens for every item i add, and it's working.
Datas for item's "model" comes from form's textboxes:
private void aggiungiClienteButton_Click(object sender, EventArgs e)
{
if (cognomeTextBox.Text == "")
{
MessageBox.Show("Uno o più campi sono vuoti");
}
else if (nomeTextBox.Text=="")
{
MessageBox.Show("Uno o più campi sono vuoti");
}
else if (indirizzoTextbox.Text == "")
{
MessageBox.Show("Uno o più campi sono vuoti");
}
else
{
clienteModel.Cognome = cognomeTextBox.Text;
clienteModel.Nome = nomeTextBox.Text;
clienteModel.Indirizzo = indirizzoTextbox.Text;
dbMemoryManager.CreateCliente(clienteModel);
cognomeTextBox.Text = String.Empty;
nomeTextBox.Text = String.Empty;
indirizzoTextbox.Text = String.Empty;
}
}
My class is:
public class ClienteModel
{
public int IDCliente { get; set; }
public string Cognome { get; set; }
public string Nome { get; set; }
public string Indirizzo { get; set; }
}
The problem is: how can i update one of those items using textboxes without changing the id?

Here's a quick and dirty solution. You don't specify what kind of textboxes you are using. I'm assuming it's Windows Forms.
I modified your ClienteModel so that it looks like this:
public class ClienteModel
{
private static int _currentId = 0;
public int IDCliente { get; set; } = _currentId++;
public string Cognome { get; set; }
public string Nome { get; set; }
public string Indirizzo { get; set; }
public override string ToString()
{
return Nome;
}
}
Note that it manages the IDCliente field now and that it has a ToString member (you can set this to whatever string you want). You may want to show the IDCliente field in a read-only textbox on your form.
Then I created a simple Windows Forms form that has your three text boxes, a ListBox named ModelsListBox and two buttons AddButton (caption: "Add") and UpdateButton ("Update").
In the form class I created a little validation method (since I use it in two places). Note that you will only get one MessageBox even if you have multiple errors:
private bool ValidateFields()
{
var errors = new List<string>();
foreach (var tb in new[] {cognomeTextBox, nomeTextBox, indirizzoTextbox})
{
if (string.IsNullOrWhiteSpace(tb.Text))
{
errors.Add($"{tb.Name} must not be empty");
}
}
if (errors.Count > 0)
{
MessageBox.Show(string.Join(Environment.NewLine, errors), "Errors", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
//otherwise
return true;
}
Then I added three event handlers (wiring them up in the normal fashion from within the designer). The first is when the Add button is pressed:
private void AddButton_Click(object sender, EventArgs e)
{
if (!ValidateFields())
{
return;
}
var model = new ClienteModel
{
Cognome = cognomeTextBox.Text,
Nome = nomeTextBox.Text,
Indirizzo = indirizzoTextbox.Text,
};
ModelsListBox.Items.Add(model);
}
It creates a new ClienteModel and adds it to the listbox (assuming validation passes).
Then, I created a handler that updates the text boxes whenever the selection in the listbox changes:
private void ModelsListBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (ModelsListBox.SelectedItem is ClienteModel model)
{
cognomeTextBox.Text = model.Cognome;
nomeTextBox.Text = model.Nome;
indirizzoTextbox.Text = model.Indirizzo;
}
}
and finally, an update button handler:
private void UpdateButton_Click(object sender, EventArgs e)
{
if (!ValidateFields())
{
return;
}
if (ModelsListBox.SelectedItem is ClienteModel model)
{
model.Cognome = cognomeTextBox.Text;
model.Nome = nomeTextBox.Text;
model.Indirizzo = indirizzoTextbox.Text;
}
}
This isn't perfect. You should disable the Update button until a selection is made (and maybe enable only after a change is made in the text box).
More importantly, the string shown in the listbox for an item is based on the results of a call to ClienteModel.ToString made when the item is first added to the list. If you change the value of a field that is used to compute .ToString, the listbox doesn't update. There are a few ways around this (findable on Stack Overflow), but I thought this would be enough to get you started.

Related

How to make a listbox display items from a checked list and radio buttons? - C# Windows Form

I'm doing a project where I am trying to simulate an ice cream parlor. For this specific section, I have the (mutually exclusive) radio buttons representing the dressing the customer can select. There are also a number of checked items (not mutually exclusive) which the customer can select in the checkedListBox. All of the items that a customer selects from the radio buttons and checkedListBox are supposed to appear in a listbox. so that the customer can keep track of all of the ordered items.
Of course, all of the code here is very unfinished and basic. I don't plan on adding any of the calculations for the prices until I make sure that the structure itself is working.
This is what I currently have so far:
private void GetToppings()
{
foreach (ListViewItem li in checkedListBox1.Items)
{
if (li.Selected == true)
{
label1.Text += li + " ";
}
}
if (checkedListBox1.SelectedItem.ToString() == "Sprinkles")
{
}
if (checkedListBox1.SelectedItem.ToString() == "Chocolate Chips")
{
}
if (checkedListBox1.SelectedItem.ToString() == "M&Ms")
{
}
if (checkedListBox1.SelectedItem.ToString() == "Oreos")
{
}
if (checkedListBox1.SelectedItem.ToString() == "Cookie Dough")
{
}
private void GetDressing()
{
if (radioButton1.Checked)
{
sDressing += "Caramel";
}
if (radioButton2.Checked)
{
sDressing += "Hot Fudge";
}
if (radioButton3.Checked)
{
sDressing += "Peanut Butter";
}
if (radioButton4.Checked)
{
sDressing += "Strawberry Syrup";
}
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i<18; i++)
{
listBox1.Items.Add(i);
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
listBox1.Items.Remove(listBox1.SelectedItem);
}
I am still very new to Windows Form programming in C#, so please forgive me if any of these questions/errors seem very basic.
The RadioButton use the following
var radioButton = Controls.OfType<RadioButton>().FirstOrDefault(x => x.Checked);
if (radioButton is not null)
{
// do something
}
For the CheckedListBox consider the following which populates via a model/class which has text and a identifier as in most cases at a later date you work with a data source this is important to keep track of items which you are not there yet but best to do it just the same.
Extension method to get items in the CheckedListBox. Place in a class file.
public static class CheckedListBoxExtensions
{
public static List<T> CheckedList<T>(this CheckedListBox sender)
=> sender.Items.Cast<T>()
.Where((_, index) => sender.GetItemChecked(index))
.Select(item => item)
.ToList();
}
Use a class/model for populating the CheckedListBox, ToString is used to display the item. Place in a class file.
public class Topping
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString() => Name;
}
Implementation
public partial class StackOverflowForm : Form
{
public StackOverflowForm()
{
InitializeComponent();
List<Topping> toppings = new List<Topping>
{
new Topping() { Id = 1, Name = "Sprinkles" },
new Topping() { Id = 2, Name = "Chocolate Chips" },
new Topping() { Id = 3, Name = "M&Ms" },
new Topping() { Id = 4, Name = "Oreos" },
new Topping() { Id = 5, Name = "Cookie Dough" }
};
checkedListBox1.DataSource = toppings;
}
private void GetToppingsButton_Click(object sender, EventArgs e)
{
List<Topping> toppings = checkedListBox1.CheckedList<Topping>();
if (toppings.Count > 0)
{
listBox1.DataSource = toppings;
}
else
{
listBox1.DataSource = null;
}
}
}

how to append to a c# list from form controls

I have a form with several text boxes. I want to use the input in the text boxes to append to a list in c# which I then want to show in a datagrid as the enteries are entered. But I have an issue. I add the data to the textboxes hit the display to datagrid button I have created and it seems ever time instead of appending items to the list the list is recreated. What am I doing wrong?
'''
{
public LotScan()
{
InitializeComponent();
}
public class LotData
{
public string Lot;
public string Description { get; set; }
public int PO { get; set; }
public string MfgPart { get; set; }
}
// code to add from control data to list
private List<LotData> LoadCollectionData()
{
List<LotData> lot = new List<LotData>();
lot.Add(new LotData()
{
Lot = LotNo.Text,
Description = frmDescription.Text,
PO = int.Parse(frmPO.Text),
MfgPart = frmMfgPart.Text,
});
return lot;
}
//button to add list data to datagrid on form
private void Button_Click(object sender, RoutedEventArgs e)
{
gridLotData.ItemsSource = LoadCollectionData();
LotNo.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmDescription.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmPO.Text = string.Empty;
}
'''
Move this variable to be a private Member variable (just put it a line above the classes constructor method):
List<LotData> lot = new List<LotData>();
public LotScan()
{
InitializeComponent();
gridLotData.ItemsSource = LotDataList;
}
private LotData LoadCollectionData()
{
return new LotData()
{
Lot = LotNo.Text,
Description = frmDescription.Text,
PO = int.Parse(frmPO.Text),
MfgPart = frmMfgPart.Text,
};
}
public class LotData
{
public string Lot;
public string Description { get; set; }
public int PO { get; set; }
public string MfgPart { get; set; }
}
public ObservableCollection<LotData> LotDataList = new ObservableCollection<LotData>();
private void Button_Click(object sender, RoutedEventArgs e)
{
LotDataList.Add(LoadCollectionData());
LotNo.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmDescription.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmPO.Text = string.Empty;
}

How to put an object list into an asp:literal?

I have a class and have added objects to a list, then binded the list to a checkboxlist. When the user checks the list, the answer goes into a new list and put in a session, then redirected to a new page. On the new page I want the result in an asp:Literal. But Im not sure how to do that.
The class:
public class Frukter
{
public string Navn { get; set; }
public string Farge { get; set; }
public string BildeSrc { get; set; }
public Frukter(string navn, string farge, string bildeSrc)
{
Navn = navn;
Farge = farge;
BildeSrc = bildeSrc;
}
}
First page:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<Frukter> frukt = new List<Frukter>();
frukt.Add(new Frukter("Appelsin", "Oransj", "~/Appelsin.jpg"));
frukt.Add(new Frukter("Banan", "Gul", "~/Banan.jpg" ));
frukt.Add(new Frukter("Eple", "Rød", "~/Eple.jpg" ));
if (!this.IsPostBack)
{
chklst.DataSource = frukt;
chklst.DataTextField = "Navn";
chklst.DataBind();
}
protected void Resultat_Click(object sender, EventArgs e)
{
List<object> ChkListe = new List<object>();
foreach (ListItem item in chklst.Items)
{
if(item.Selected)
// If the item is selected, add the value to the list.
ChkListe.Add(item);
}
Session["selectedChkList"] = ChkListe;
Response.Redirect("Default2.aspx", false);
}
}
Second page where I take the list out of session, but not sure how to get it into the asp:literal.
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<object> ResultatList = new List<object>();
if (Session["selectedChkList"] != null)
{
ResultatList = (List<object>)Session["selectedStrList"];
ResultatLliteral.Text = String.Format("<p>{0} {1}</p> <img src ={3} />", Frukter.Navn, Frukter.farge, Frukter.BildeSrc);
}
}
}
}
Some critique on your code and some different approaches, not sure what your assignment is but I'll provide feedback that may be beneficial for your course.
public class Fruit
{
public Fruit(string name, string color, string image)
{
Name = name;
Color = color;
Image = image;
}
public string Name { get; }
public string Color { get; }
public string Image { get; }
}
You defined a Constructor that will always set a value upon creation, so unless you intend to modify the object after the fact you can set your properties to read only.
Personally I would use a database or another way to persist my data, but for your example you should be able to do the following:
var fruits = new List<Fruit>()
{
new Fruit("Apple", "Red", "..."),
new Fruit("Grapefuit", "Yellow", "...")
};
// Grab the selected checkbox in the checkbox list item (You'll have to see if a collection is returned or not)
var selectedFruit = chkLFruit.Items.Cast<ListItem>().Where(item => item.Selected);
// Take selected item and pass full object into session.
var filter = fruits.Where(fruit => selectedFruit.Select(t => t.Text).FirstOrDefault(x => String.Compare(x, fruit.Name, true) == 0);
// Create Session
HttpContext.Session["FruitSelection"] = filter;
On your other page before you attempt to use simply do the following:
var selectedFruits = (List<Fruit>)HttpContext.Session["FruitSelection"];

SelectedValue in Combobox after double click datagridview

I've a datagridview which has values from 2 Tables.
When I double click on a row, I need to pass those values to another form.
That form has textbox and a Combobox which contains values from a table which gives me all need value to select.
For the textboxes, no problem at all, but for the combobox, that's a real pain.
But I need this ComboBox gets the Selected Value from the datagridview, but it allways turns the first value from the list.
Here's my code for double ckick event in the datagridview.
Can please someone help me making this work?
This is a Windows Forms project.
public System.Data.DataTable ContratosTable { get; set; }
public void LoadContratosTable()
{
ContratosTable = new System.Data.DataTable();
using (var cn = new SqlConnection { ConnectionString = ConfigurationManager.ConnectionStrings["IWMConnectionString"].ConnectionString.ToString() })
{
using (var cmd = new SqlCommand { Connection = cn })
{
cn.Open();
cmd.CommandText = "SELECT IdContrato, Designacao FROM dbo.Contratos";
ContratosTable.Load(cmd.ExecuteReader());
}
}
}
private void concelhos_datagrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
BindingSource bs = new BindingSource();
LoadContratosTable();
bs.DataSource = ContratosTable;
Concelhos_Edit f = new Concelhos_Edit();
f.txt_id.Text = concelhos_datagrid.CurrentRow.Cells[0].Value.ToString();
var _nomeContrato = ContratosTable.AsEnumerable().FirstOrDefault(a => a.Field<int>("IdContrato") == ((DataRowView)bs.Current).Row.Field<int>("IdContrato")).Field<string>("Designacao");
var pos = f.cmb_contrato.FindString(_nomeContrato);
if (pos > -1)
{
f.cmb_contrato.SelectedIndex = pos;
}
f.txt_sigla.Text = concelhos_datagrid.CurrentRow.Cells[2].Value.ToString();
f.txt_nome.Text = concelhos_datagrid.CurrentRow.Cells[3].Value.ToString();
f.txt_codigo.Text = concelhos_datagrid.CurrentRow.Cells[4].Value.ToString();
f.txt_qservico.Text = concelhos_datagrid.CurrentRow.Cells[5].Value.ToString();
f.chk_ativo.Checked = (bool)concelhos_datagrid.CurrentRow.Cells[6].Value;
f.MdiParent = this.MdiParent;
f.Show();
}
This will point, and help, you in the right direction. Try and follow either MVC or MVVM and the design will help you keep the concerns separate and you will end up with better and cleaner code.
For now, create a class like shown below:
public class Info
{
public Info()
{
this.NomeContrato = new List<string>();
}
public string Id { get; set; }
public string Sigla { get; set; }
public string Nome { get; set; }
public string Codigo { get; set; }
public string QServico { get; set; }
public bool Ativo { get; set; }
public List<string> NomeContrato { get; set; }
}
Then add this property to the Concelhos_Edit class:
public Info Model { get; set; }
Also add this code to _Load handler of Concelhos_Edit form:
this.cmb_contrato.DataSource = this.Model.NomeContrato;
// If you need the SelectedValue from the other form, then add another
// property to Info class and put the value there.
// this.cmb_contrato.SelectedValue = this.Model.SelectedValue;
this.cmb_contrato.SelectedValue = "whatever you want to be selected";
Then, modify the cell double click method named: concelhos_datagrid_CellDoubleClick to look like below:
private void concelhos_datagrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// Your code...
var editForm = new Concelhos_Edit();
var editFormModel = new Info();
editFormModel.Id = f.txt_id.Text = concelhos_datagrid.CurrentRow.Cells[0].Value.ToString();
// Set other properties
// Here is the work for dropdown
var _nomeContrato = ContratosTable.AsEnumerable().FirstOrDefault(a => a.Field<int>("IdContrato") == ((DataRowView)bs.Current).Row.Field<int>("IdContrato")).Field<string>("Designacao");
editFormModel.NomeContrato.AddRange(_nomeContrato);
formEdit.Model = editFormModel;
formEdit.MdiParent = this.MdiParent;
formEdit.Show();
}
Please use this code as a guide and you may need to tweak it. The idea is to pass the information the form needs, and then let that form do whatever with the information: whether it wants to show the information in a TextBox or RadioButton is that form's business.

Reflect changes from BindingList.List.Element between controls and the Bindinglist

I have a BindingList of objectAs bound to comboBox_1.DataSource (and object's name as DisplayMember). My objectA consists of objectZ and a list of objectXs. The form is connected to one specific element from that objectXs list. There are many other controls on this form which show values of different properties of objectX.
Here's some code to visualize that:
class objectA
{
class objectZ
{
public int Count { get; set; }
}
class objectX
{
public string Prop1 { get; set; }
public bool Prop2 { get; set; }
}
public string Name { get; set; }
public objectZ Z { get; set; }
public List<objectX> listX { get; set; }
}
BindingList<objectA> listA = new BindingList<objectA>();
comboBox_1.DataSource = listA;
comboBox_1.DisplayMember = "Name";
How do I make it so objectX values in other controls change to reflect currently chosen value in comboBox while retaining the BindingList property of reading/writing data 'on-the-go'? To express it in code (aka What I'm trying to achieve):
textBox_1.Text = listA.GetWantedObjectX().Prop1;
checkBox_1.Checked = listA.GetWantedObjectX().Prop2;
void checkBox_1_CheckedChanged()
{
listA.GetWantedObjectX().Prop2 = checkBox_1.Checked;
}
I'm guessing I'd need a objectA.objectX currentObject property to control the data and then it'd be:
currentObject = listA.GetWantedObjectX();
checkBox_1.Checked = currentObject.Prop2;
But then changes made to currentObject would not be reflected in listaA and I'd have to create sth like a save button, right? Is there a more 'responsive' way?
While it's not a pretty solution (noone provided a better one), I basically sticked with that currentObject and controlling everything inside a comboBox1_SelectedIndexChanged event. Here's the code for that:
objectA.objectX currentObject = null;
int previousObjectIndex = 0;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (currentObject == null)
{
currentObject = listA[comboBox1.SelectedIndex].GetWantedObjectX();
textBox1.Text = currentObject.Prop1;
}
else
{
currentObject.Prop1 = textBox1.Text;
if (!listA[previousObjectIndex].listX.Any(x => x.Prop1 == currentObject.Prop1))
listA[previousObjectIndex].listX.Add(currentObject);
currentObject = listA[comboBox1.SelectedIndex].GetWantedObjectX();
if (currentObject == null)
currentObject = new objectA.objectX();
previousObjectIndex = comboBox1.SelectedIndex;
textBox1.Text = currentObject.Prop1;
}
}
Of course this does not include handling of objectZ, where a similiar mechanic would need to be introduced.

Categories