Prevent adding duplicate snack to ListView - c#

I'm currently stuck on this for 2 hours and did everything I could to find answers but none yet!
public class Snack
{
public string snack { get; set; }
public double amount { get; set; }
public int price { get; set; }
public Snacks snacks;
public enum Snacks
{
friet,
kroket,
frikandel,
Burger,
}
}
In the load method, I'm initializing my ListView:
private void load()
{
lstSnacks.View = View.Details;
lstSnacks.Columns.Add("snack");
lstSnacks.Columns.Add("amount");
lstSnacks.Columns.Add("price");
cmbSnack.Items.AddRange(Enum.GetNames(typeof(Snack.Snacks)));
cmbSnack.SelectedIndex = (int)Snack.Snacks.friet;
}
After that, I have a button where I add some snacks with the amount entered in the textbox and a fixed price:
private void btnAdd_Click(object sender, EventArgs e)
{
if (!lstSnacks.Items.ContainsKey(cmbSnack.SelectedItem.ToString()))
{
double totalprice = 0;
Snack snack1 = new Snack();
snack1.snack = cmbSnack.SelectedItem.ToString(); ;
snack1.amount = Convert.ToDouble(txtAmount.Text);
ListViewItem item = lstSnacks.Items.Add(cmbSnack.SelectedItem.ToString());
item.SubItems.Add(snack1.amount.ToString());
if (cmbSnack.SelectedIndex == 0)
{
snack1.price = (int)(snack1.amount * 2.50);
item.SubItems.Add(snack1.price.ToString());
}
}
I need to look into my ListView and add a snack if it's not already there. If it is, it should tell you that it's already in there, but items.ContainsKey is not working for me properly. What am I doing wrong?

The line...
ListViewItem item = lstSnacks.Items.Add(cmbSnack.SelectedItem.ToString());
...sets the Text property of the ListViewItem. To be able to use ContainsKey(), you need to also set its Name property.
One more thing: Consider using double.TryParse() instead of Convert.ToDouble() because there's no guarantee that the user will enter a valid number. When dealing with user input, always favor the .TryParse() methods over Convert.ToXXXX() or .Parse().
I would change the code into something like this:
string itemName = cmbSnack.SelectedItem.ToString();
if (lstSnacks.Items.ContainsKey(itemName))
{
MessageBox.Show("The item already exists in the list.", "Duplicate item");
return;
}
if (!double.TryParse(txtAmount.Text, out double amount))
{
MessageBox.Show("Please enter a valid amount.", "Incorrect 'Amount' value");
return;
}
double totalprice = 0;
Snack snack1 = new Snack();
snack1.snack = itemName;
snack1.amount = amount;
ListViewItem item = lstSnacks.Items.Add(itemName);
item.Name = itemName;
item.SubItems.Add(snack1.amount.ToString());
if (cmbSnack.SelectedIndex == 0)
{
snack1.price = (int)(snack1.amount * 2.50);
item.SubItems.Add(snack1.price.ToString());
}

Related

Declaring the datasource of another formBox, by the currently selected listBox item

Apologies if this has been asked already,
I want to know how to declare the datasource of a textbox or a listbox by the currently selected listBox object.
So box 1 has the list of items, and each selection prints to the next box with more information about them (ItemInfo)
Here is my code that I'm working with:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex != null)
{
listBox2.DataSource = ItemStorage._?_?_?_?_(listBox1.SelectedItem);
}
}
public class ItemObject
{
public string ItemName { get; set; }
public string ItemInfo { get; set; }
public ItemObject(string itemName, string itemInfo)
{
ItemName = itemName;
ItemInfo = itemInfo;
}
public override string ToString()
{
return ItemName;
}
}
The list name is ItemStorage and the element I want to print to the other box is ItemInfo.
I have found the answer I was looking for:
Instead of using a listBox, I opted for a richTextBox and this is the code I used:
if (listBox1.SelectedIndex != null)
{
try { var Information = ((ItemObject)listBox1.SelectedItem).ItemInfo;
richTextBox2.Text = Information;
}
catch( Exception ex)
{
}
}
This provided me with only getting the information from the selected item I wanted to have, so my listbox has a full total of all the items, while the selection only shows me the information from the one ive selected.

Return get set method value to label

In my Windows form I have 2 text boxes namely, start odometer reading and end odometer reading. My goal is to subtract the "start reading" from the "end reading" and display the difference in the label next to the Name and phone number of the client in the windows form label.
How do I return the value of the method getMilesCharge() and display it on the confirmLabel?
Code for the Car Rental Class
//A class that represents the Rental Agency Class.
namespace Assignment1
{
partial class RentalAgencyClass
{
//instance variables
public string customerName { get; set; }
public string phoneNumber { get; set; }
public double sMiles { get; set; }
public double eMiles { get; set; }
public double noOfDays { get; set; }
private double DAY_CHARGE = 15;
private double MILE_CHARGE = 0.12;
//Constructor class
//sets the value of the starting and ending miles.
//sets the value of the number of days the car was rented for
public RentalAgencyClass(double startMiles, double endMiles, double days)
{
startMiles = sMiles;
endMiles = eMiles;
days = noOfDays;
}
//method to calculate the number of miles driven on the rental
public double getMileCharge()
{
double milesDriven = 0;
milesDriven = eMiles - sMiles;
return milesDriven * MILE_CHARGE;
}
//method to calculate the Day Charges on the rental
public double getDayCharge()
{
return noOfDays * DAY_CHARGE;
}
//Property to display the information on the label
public string GetInfo()
{
return customerName + " | " + phoneNumber + " | " + getDayCharge() +" miles";
}
}
}
Form Designer Class code
namespace Assignment1
{
public partial class RentalAgencyClass : Form
{
RentalAgencyClass aCarRental;
public RentalAgencyClass()
{
InitializeComponent();
}
private void calculateButton_Click(object sender, EventArgs e)
{
try
{
//instantiates object
aCarRental = new RentalAgencyClass();
aCarRental.customerName = nameTextBox.Text;
aCarRental.phoneNumber = phoneTextBox.Text;
//aCarRental. = getDayCharge();
// aCarRental.milesDriven = //store the difference in this variable
//displayLabel.Text = "(student information saved)";
}
catch (Exception err)
{
MessageBox.Show(err.Message, "Error");
}
//Displays information about the Rental
confirmLabel.Text = aCarRental.GetInfo();
}
}
}
By calling aCarRental = new RentalAgencyClass(); within your calculateButton_Click method you are calling the parameterless constructor of your partial class RentalAgencyClass, which means in your case, you are creating a new instance of your form instead of setting your properties. So sMiles and eMiles will stay by their default value 0.
To get your code working you have to do several steps.
At first I recommend you should split your form and your agency class.
So let's say, rename your form class to RentalCalculator. As a next step you have to/can remove the partial from your RentalAgencyClass, because it is not a part of your form class anymore and I assume you did not want to extend your class in another part of your code.
As LarsTech pointed out in the comments. You should now fix your RentalAgencyClass constructor to:
public RentalAgencyClass(double startMiles, double endMiles, double days)
{
this.sMiles = startMiles;
this.eMiles = endMiles;
this.noOfDays = days;
}
and may add the following property to your class
public double milesDriven
{
get
{
return this.eMiles - this.sMiles;
}
}
At least you have to change your event handler:
private void calculateButton_Click(object sender, EventArgs e)
{
try
{
// if not existing you have to create some input textboxes
double startMiles = Convert.ToDouble(startMilesTextBox.Text);
double endMiles = Convert.ToDouble(endMilesTextBox.Text);
double days = Convert.ToDouble(daysTextBox.Text);
// Hint: you are creating a new instance on every button click
// and overwriting your field in your form class.
aCarRental = new RentalAgencyClass(startMiles, endMiles, days);
aCarRental.customerName = nameTextBox.Text;
aCarRental.phoneNumber = phoneTextBox.Text;
// Store the result in local variables
// if you want to do something with them later
double dayCharge = aCarRental.getDayCharge();
double milesCharge = aCarRental.getMilesCharge();
double drivenMiles = aCarRental.milesDriven;
// displayLabel.Text = "(student information saved)";
}
catch (Exception err)
{
MessageBox.Show(err.Message, "Error");
}
//Displays information about the Rental
confirmLabel.Text = aCarRental.GetInfo();
}
Answering your question:
How do I return the value of the method getMilesCharge() and display it on the confirmLabel?
You will have to change the following line in your calculateButton_Click method from:
confirmLabel.Text = aCarRental.GetInfo();
to:
confirmLabel.Text = aCarRental.getMilesCharge().ToString();
Last but not least let me give you a kind advice.
You may take a look at the Microsoft Naming Guidelines.
For example: Properties should be named in PascalCasing.
But this is just my personal opinion.

Can't show the text in DataGridViewButtonColumn

I've try to practice with "DataGridViewButtonColumn" property.
But here is a strange problem that I can't display the text in button in first column.
ScreenShot:
I try it in different methods, but it still not working.
Here is my code snippet.
Thanks ^__^
private void Form1_Load(object sender, EventArgs e)
{
Demo d;
List<Demo> list = new List<Demo>();
for (int i = 0; i < 10; i++)
{
d = new Demo();
d.No = i.ToString();
d.Name = "A" + i;
list.Add(d);
}
foreach (Demo item in list)
dataGridView1.Rows.Add(item.No, item.Name);
}
public struct Demo
{
public string No { get; set; }
public string Name { get; set; }
}
Read up on DataGridViewButtonColumn.UseColumnTextForButtonValue.
Set the value to false to get your desired results:
this.Column1.UseColumnTextForButtonValue = false;
Setting it to true means that it will use DataGridViewButtonColumn.Text for every button's text value (which you didn't set - and therefore shows blank text on all buttons). For example:
this.Column1.UseColumnTextForButtonValue = true;
this.Column1.Text = "Click Here";

C# meetings system

I'm creating a form to hold information from "meetings". The user will fill out info regarding title, location, startTime, endTime, notes, and a date. What I am currently working on is the "save changes" button which will:
clear all the TextBoxes.
store the input in an array.
display only the title in the ListBox.
when the title is clicked on in the ListBox, the info stored in that array element re-populates in the appropriate TextBoxes should the user wish to make changes.
I have completed #1, #2 and #3 I would appreciate any help for #4. I've pasted the coding below for your viewing.
public partial class CalendarForm : Form
{
int currentIndex;
int arraySize = 0;
Meeting[] meetingArray = new Meeting[100];
public CalendarForm()
{
InitializeComponent();
}
private void saveChangesButton_Click(object sender, EventArgs e)
{
meetingArray[arraySize] = new Meeting();
meetingArray[arraySize].title = textBoxTitle.Text;
meetingArray[arraySize].location = textBoxLocation.Text;
meetingArray[arraySize].startTime = textBoxStartTime.Text;
meetingArray[arraySize].endTime = textBoxEndTime.Text;
meetingArray[arraySize].notes = notesTextBox.Text;
currentIndex = arraySize;
arraySize++;
meetingListBox.Enabled = true;
textBoxTitle.Text = "";
textBoxLocation.Text = "";
textBoxStartTime.Text = "";
textBoxEndTime.Text = "";
notesTextBox.Text = "";
*edit* added these two lines which now add the title to the listBox
meetingListBox.Items.Add(meetingArray[currentIndex].title);
Controls.Add(meetingListBox);
}
}
public class Meeting
{
public string title;
public string location;
public string startTime;
public string endTime;
public string notes;
};
This is how I would refactor the class:
public partial class CalendarForm : Form
{
private List<Meeting> Meetings { get; set; }
public CalendarForm()
{
InitializeComponent();
Meetings = new List<Meeting>();
}
private void saveChangesButton_Click(object sender, EventArgs e)
{
try
{
Meeting meeting = CreateMeeting();
Meetings.Add(meeting);
meetingListBox.Add(meeting);
}
catch
{
//Add proper error handling here
}
}
private Meeting CreateMeeting()
{
return new Meeting()
{
Title = textBoxTitle.Text,
Location = textBoxLocation.Text
StartTime = DateTime.Parse(textBoxStartTime.Text),
EndTime = DateTime.Parse(textBoxEndTime.Text),
Notes = notesTextBox.Text,
};
}
}
//As Matt Burland answered already:
private void meetingListBox_SelectedIndexChanged(object sender, EventArgs e)
{
Meeting meeting = meetingListBox.SelectedItem as Meeting;
if (meeting != null)
{
textBoxTitle.Text = meeting.Title;
//...etc for all your other text boxes.
}
}
public class Meeting
{
public string Title { get; set; }
public string Location { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string Notes { get; set; }
public override string ToString()
{
return Title;
}
}
I've made a number of changes, more notably the switch from an Array to a List<>. Lists are more flexible and provide better functionality. Unless you really really need to use arrays, I would stay away from them just to better safeguard against logic errors index out of bounds type issues.
Also, I personally believe that dates should be stored in the DateTime struct format, but that is again a matter of preference. Note that it would be prudent to sanitize/validate the inputs (especially the dates) before assigning it into the Meeting object.
The Meeting object now has properties instead of public fields. Properties are preferred in case you ever want to change how something is Get/Set.
Hope this helps.
I really recommend you look up data binding and learn how to do this properly, but if you want a quick and dirty solution (although, in the end, you'll find it's a lot more work), I would do something like this:
private void saveChangesButton_Click(object sender, EventArgs e)
{
Meeting m = new Meeting();
m.title = textBoxTitle.Text;
m.location = textBoxLocation.Text;
m.startTime = textBoxStartTime.Text;
m.endTime = textBoxEndTime.Text;
m.notes = notesTextBox.Text;
meetingArray[arraySize] = m;
currentIndex = arraySize;
arraySize++;
meetingListBox.Enabled = true;
textBoxTitle.Text = "";
textBoxLocation.Text = "";
textBoxStartTime.Text = "";
textBoxEndTime.Text = "";
notesTextBox.Text = "";
meetingListBox.Items.Add(m);
//Controls.Add(meetingListBox); // You don't need to keep adding the control every time!
}
Now in your Meeting class, I'd override ToString() to just return the title. The ListBox will just use the ToString() method of whatever you add to it by default.
To help with #4, you want to bind the SelectedIndexChanged event and then use the SelectedItem property, cast it back to a Meeting object (because it'll return an Object) and then use it to repopulate your various text boxes.
Something like:
private void meetingListBox_SelectedIndexChanged(object sender, System.EventArgs e)
{
Meeting m = meetingListBox.SelectedItem as Meeting;
if (m != null)
{
textBoxTitle.Text = m.title;
//...etc for all your other text boxes.
}
}

Formating DataGridView Columns for an unbound data source

I am struggling with the WinForms DataGridView. I have a class, that I use as element to be displayed:
public class BorderFlowHistoryElement
{
public string nodeTitles { get; set; }
public double borderFlowRatio { get; set; }
...
}
I created a list of these elements:
List<BorderFlowHistoryElement> clusterHistory
which contains a list of thise elements, that should be displayed in my DataGridView. I bound the list at the DataSource of the Grid:
dataGridViewCluster.DataSource = clusterHistory;
Now the DataGridView displays the list. Now I want to format the columns which display the double values to display 5 digits. I tried it with:
dataGridViewCluster.Columns[1].DefaultCellStyle.Format = "n5";
but this has no effect on the column. Anyone knows, how I can do it right?
Additionally, I want to size the columnwidth to optimal fit for the largest entry.
Thanks in advance,
Frank
I have replicated what you have done and I had no issue whatsoever. Have you validated your data to ensure that you can actually get the results that you want?
Here is what I did just for your reference:
private void button1_Click(object sender, EventArgs e)
{
IList<BorderFlowHistoryElement> clusterHistory = FillClusterHistory();
dataGridView1.DataSource = clusterHistory;
dataGridView1.Columns[1].DefaultCellStyle.Format = "n5";
dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
}
private static IList<BorderFlowHistoryElement> FillClusterHistory()
{
IList<BorderFlowHistoryElement> clusterHistory = new List<BorderFlowHistoryElement>();
for(int i = 5000; i < 5020; i++)
{
BorderFlowHistoryElement element = new BorderFlowHistoryElement();
element.nodeTitles = Guid.NewGuid().ToString();
element.borderFlowRatio = i * 3.3.1415672467234823499821D;
clusterHistory.Add(element);
}
return clusterHistory;
}
}
public class BorderFlowHistoryElement
{
private string _NodeTitles;
private double _BorderFlowRatio;
public string nodeTitles
{
get { return _NodeTitles; }
set { _NodeTitles = value;}
}
public double borderFlowRatio
{
get { return _BorderFlowRatio; }
set { _BorderFlowRatio = value;}
}
}
I hope that helps in some fashion. As you can see you can do the auto sizing as well.

Categories

Resources