C# listbox item identification - c#

Keep in mind, i am not very experienced with c#.
I am coding a remove button for a list box and the basic function of removing the selected item works.
listBoxSum.Items.RemoveAt(listBoxSum.SelectedIndex);
I'm trying to make an IF statement which will allow me to select an item from my list-box and have it identify the text inside of it (Most likely a string).
As i don't know too much about c#, this is what i currently have for the if statement (obviously the first line is error).
if (listBoxSum.SelectedItem = "Tea")
{
totalCost = totalCost - teaCost;
txtBox_Amount.Text = totalCost.ToString();
}
I have tried making other strings to help simplify the statement like (Below is not the main piece of code for the if statement, the above code is. This was just an experiment on try and extend the code to make it a bit more understandable for myself):
string teaSelect = "Tea" + teaCost;
string selection = (string) listBoxSum.SelectedItem;
if (selection == teaSelect)
{
totalCost = totalCost - teaCost;
txtBox_Amount.Text = totalCost.ToString();
}
Please help, i don't know whether i should change how i'm thinking about this or if it an easy fix hiding in plain sight. Personally i have been stumped on this little button for around 2 hours figuring out how i am going to make the remove button work with the calculations.

If you are not updating your item that holds the "Tea + cost" value, you should probably identify it either by string.StartsWith or maybe assigning it with an identifier of your choice. This could be an integer, an enum or another concrete class with predefined instances.
You can do this by using the Tag property for WPF and creating a simple class for Windows Forms (WPF Tag Property).
A simple example for Windows Forms would be:
enum FoodType
{
Tea = 2
}
class FoodItem
{
public string Text { get; set; }
public FoodType FoodType { get; set; }
public override string ToString()
{
return Text;
}
}
When you are adding your items:
listBoxSum.Items.Add(new FoodItem
{
FoodType = FoodType.Tea,
Text = "Tea " + teaCost
});
And when you are filtering them:
if (listBoxSum.SelectedItem is FoodItem foodItem && foodItem.FoodType == FoodType.Tea)
{
// Do work
}
It is even easier for WPF:
enum FoodType
{
Tea = 1
}
Adding items:
listBoxSum.Items.Add(new ListBoxItem
{
Content = "Tea " + teaCost,
Tag = FoodType.Tea
});
Identifying items:
if (listBoxSum.SelectedItem is ListBoxItem foodItem && foodItem.Tag is FoodType foodType && foodType == FoodType.Tea)
{
MessageBox.Show("hi");
}

What you want to check is whether the item you are currently looking at is a ListBoxItem, and if so, is the contained content a text and is this text equal to your desired text, in order to identify the correct item.
var content = (((x.SelectedItem as ListBoxItem)?.Content as string);
if (content != null && content == "MyDesiredText") {...}
This would be a valid, but not an elegant solution.
A better way would be to remember the listbox items while creating them
var desiredListBoxItem = new ListBoxItem(...)
x.AddChild(desiredListBoxItem);
and afterwards, check whether the object references match:
if (x.SelectedItem == desiredListBoxItem) {...}

So your item in ListBox is called "Tea"?If it is your if statement should look something like this:
if(yourTextBox.Items[yourTextBox.SelectedIndex] == "Tea")
{
//Your Code
}

Related

C# - How do I set the selected item in a combobox by comparing my int value?

I'm using a ComboBox with items having text and value. Now, I want to simply make an item selected by comparing its value with the provided value. I'm iterating through the items and comparing as follow. Below code works fine, but is there a better or more simpler way to do this? I found a possible duplicate here but it works with the string value not integer.
foreach (ComboboxItem item in this.CampaignList.Items)
{
if (Convert.ToInt16(item.Value) == objAACampaign.CompanyId)
{
this.CampaignList.SelectedIndex = this.CampaignList.Items.IndexOf(item);
break;
}
}
Use display and value memeber
Create custom class like this:
class MyCustomClass
{
//important to have get set part
public _int { get; set; }
public _string { get; set; }
}
now load data you want to display inside List<MyCustomClass>() and then bind that list to combobox and set it's display and value member like this:
myComboBox.DisplayMember = "_string";
myComboBox.ValueMember = "_int";
myComboBox.DataSource = myList; //this is List<MyCustomClass>
Now simply use myComboBox.SelectedValue = valueYouWant
IMPORTANT!!!
Declare displayMember and valueMember before binding datasource to combobox because of perfomance. Search internet for more info.

C# Changing a part of a line of code to a variable

I am using Unity3D.
I have a script to sort a list based on a certain value of a creature.
For example, the creatures have a variable saying how much food they've eaten, how many calories they currently have, and how large they are.
I want the user to be able to change the way the values are sorted by clicking a button. I don't want to pile if statements though, such as
if(sortType == "calories") {
entrySortedText.text = creatureData.calories.ToString();
} else if(sortType == "food eaten") {
entrySortedText.text = creatureData.foodEaten.ToString();
}
I want to be able to do something like
entrySortedText.text = creatureData.sortType.ToString();
to automatically find the variable with the name of what the sort type is in creatureData. But obviously this doesn't work, as there is no variable "sortType" in creature data, but I want it to replace what the sortType is automatically with the variable name, such as "calories" or "food eaten".
Does anyone know a way to change a part of a line of code to the value of a variable? Or do I have to just use a bunch of if statements?
Thanks. Your response is greatly valued.
P.S.
Here is the current sorting code:
public void LoadList() {
foreach(Transform child in transform) {
GameObject.Destroy(child.gameObject);
}
List<GameObject> creatures = new List<GameObject>(GameObject.FindGameObjectsWithTag("Creature").ToList());
// Sort list based on calories
creatures.Sort(
delegate(GameObject i1, GameObject i2) {
return i2.GetComponent<CreatureData>().calories.CompareTo(i1.GetComponent<CreatureData>().calories);
}
);
foreach(GameObject creature in creatures) {
GameObject entry = Instantiate(entryPrefab);
entry.transform.SetParent(transform, false);
entry.transform.GetChild(0).GetComponent<Text>().text = creature.GetComponent<CreatureData>().creatureName;
entry.transform.GetChild(1).GetComponent<Text>().text = creature.GetComponent<CreatureData>().calories.ToString();
entry.GetComponent<CreatureListEntryButton>().targetCreature = creature;
}
}
So you want to sort on a property but that property will be decided at runtime.
Let's say you have a collection named items and the items have a property named Calories. Then you can do this:
var sortBy = "Calories";
var propertyInfo = typeof(YourObject).GetProperty(sortBy);
Then you can sort on that:
var orderByCalories = items.OrderBy(x => propertyInfo.GetValue(x, null));

Check if list view contain item

i have a listview with 3 columns (id , name, author), i use this method to add row:
public void addToLv(Book book)
{
//TODO: Verifier si l'item existe avant d'ajouter
ListViewItem lvi1 = new ListViewItem(book.id.ToString());
lvi1.Text = book.id.ToString();
lvi1.SubItems.Add(book.name);
lvi1.SubItems.Add(carte.author);
listView1.Items.Add(lvi1);
}
Now i wan't to check if book exists before i insert the new one to avoid duplicate element, i try this code but it'S not working
i have use this line but it's not working:
(listView1.Items.ContainsKey(book.id))
{
listView1.Items.Add(lvi1);
}
Can you help me please? thank you
From MSDN:
The key comparison is not case-sensitive. The Name property corresponds to the key for a ListViewItem in the ListView.ListViewItemCollection.
So, you have to set the Name in order to use ContainsKey
lvi1.Name = book.id.ToString();
And then the rest like you did:
if (!listView1.Items.ContainsKey(book.id.ToString()))
{
listView1.Items.Add(lvi1);
}
I think you missed a "!" (not) in your code.
(!listView1.Items.ContainsKey(book.id))
{
listView1.Items.Add(lvi1);
}
Your code is saying that if your listview contains that key, you will add another entry that has that key. But it seems you want to do the opposite, right? If your listview does not contain an entry with that key, you want to add an entry that has that key.
It looks like you are storing your individual names on the SubItems property, so you'll need to query that to see if a given book name is present. You can do this using a bit of LINQ as follows:
// If your ListView doesn't contain any items that have a given book as a SubItem
// then add one
if (!listView1.Items.Any(i => i.SubItems.ContainsKey(book.Name))
{
listView1.Items.Add(lvi1);
}
Since your edit indicates that you actually want to check for the ID instead, which is stored at the ListItem-level, then you would just need to slightly adjust your condition to check the Text property since the ListViewItem(string) constructor sets the Text property by default:
if (!listView1.Items.Any(i => i.Text == book.id))
{
listView1.Items.Add(lvi1);
}
If any thing works, try this:
public void addToLv(Book book)
{
//TODO: Verifier si l'item existe avant d'ajouter
ListViewItem lvi1 = new ListViewItem(book.id.ToString());
//lvi1.Text = book.id.ToString();
lvi1.SubItems.Add(book.name);
lvi1.SubItems.Add(carte.author);
if (!existChecker(book.id.ToString()))
listView1.Items.Add(lvi1);
}
private bool existChecker(string id)
{
bool exist = false;
for (int i = 0; i < lvi1.Items.Count && exist != true; i++)
{
if (lvi1.Items[i].SubItems[0].Text == id)
exist = true;
}
return exist;
}
LINQ can't be used for this:
if (!listView1.Items.Any(i => i.SubItems.ContainsKey(book.Name))
The only real way of doing it is to use the search functionality as thus:
if (listView1.FindItemWithText(book.Name) != null)
{
// Do the business...
}
etc...

How can I output a list of field names and values that were changed?

I'm still learning C# whilst building an MVC web app. Trying to find a way to create a list of values that were changed by a user during an edit operation.
Here's one way I have that would work:
public List<string> SaveVehicleTechnicalInformation(VehicleAssetTechnicalInformationViewModel editmodel)
{
// Create a list of fields that have changed
List<string> changes = new List<string>();
var record = db.VehicleAssetTechnicalInformations.Find((int)editmodel.RecordID);
if (editmodel.Make != null && editmodel.Make != record.Make)
{
changes.Add(" [Make changed from " + record.Make + " to " + editmodel.Make + "] ");
record.Make = editmodel.Make;
}
if (editmodel.Model != null && editmodel.Model != record.Model)
{
changes.Add(" [Model changed from " + record.Model + " to " + editmodel.Model + "] ");
record.Model = editmodel.Model;
}
return changes;
}
But... As you can tell, I am going to need to write an IF/ELSE statement for every single field in my database. There are about 200 fields in there. I'm also worried that it's going to take a long time to work through the list.
Is there some way to go through the list of properties for my object iteratively, comparing them to the database record, changing them if necessary and then outputting a list of what changed.
In pseudo code this is what I guess I am after:
foreach (var field in editmodel)
{
if (field != database.field)
{
// Update the value
// Write a string about what changed
// Add the string to the list of what changed
}
}
Because I'm still learning I would appreciate guidance/tips on what subject matter to read about or where I can independently research the answer. The gaps in my skill are currently stopping me from being able to even research a solution approach.
Thanks in advance.
You can try to use Reflection for your purposes. Something like this
var fields = editmodel.GetType().GetFields();
foreach (var item in fields)
{
if (item.GetValue(editmodel) == database.field)
{
// Update the value
// Write a string about what changed
// Add the string to the list of what changed
}
}
I think I have found the hint I was looking for...
System.Reflection
More specifically, the FieldInfo.GetValue() method.
I was previously unaware of what System.Reflection was all about, so I'll research this area further to find my solution.

Remove a property/column from a generic list

Due to some reason I cannot change the query so I have to do this in C#.
I have a class:
public class myClass
{
int id { get; set; }
string name { get; set; }
DateTime sDate { get; set; }
bool status { get; set; }
}
The data I am getting is fetched in this list. Now what I want is to remove those properties from a list that has null values. I may sound insane but you read it right. I thought of creating another list with only the selected properties, but any of the above properties can be null. So I have to devise a mechanism to filter my list based on this.
For more clarity consider the following example.
List<myClass> lstClass = some data source.
After getting the data the generic list(lstClass) looks like this.Consider the result set in a table:
Id Name Sdate status
1 a null null
2 b null null
3 c null false
Can i some how make my list look like this after removing the property sdate.
So the new list that I want to create should have only three properties.
Id Name status
1 a null
2 b null
3 c false
Any ideas? Can I do this using Linq?
PS: This has nothing to do with presentation. I don’t have a grid where I am not able to hide columns that Is not what I am looking for.
Assuming you have a generic list of myClass instances, you can create an anonymous type with only the needed properties:
List<myClass> list = ...;
var reducedList = list.Select(e => new {e.id, e.name, e.status}).ToList();
// note: call to ToList() is optional
foreach (var item in reducedList)
{
Console.WriteLine(item.id + " " + item.name + " " + item.status);
//note: item does not have a property "sDate"
}
I'm not sure you should solve your issue in the Data, but rather it's a presentation problem.
In which control do you want to display it ? Let's say you display it in DataGrid with AutoGenerateColumns=True, then you can 1) loop on columns/properties 2) for each column/property see if all property values for all rows are null and if so set column's visibility to Collapsed.
If you generate your columns by yourself it's even simpler : only add columns when content is not null for all rows.
If your DB content is dynamic, you might want to bind each row's visibility to a property that would state wether all rows are null or not for that property. Depending on how generic you want your code to be, the code might be very different, and in case you want to have generic solution, using Reflection to retrieve/get/set properties might be of some use.

Categories