ComboBox keeps old values while displaying new ones - c#

So, it's been 4 hours since I started struggling here.
See, I've got this comboBox and it's bound to a List<>, - loads up like it's supposed to; but here I've also got a textBox which is supposed to contain text for filter criteria of the List<>. Goes nice, packs all the filtered items into a new list, the comboBox displays it... But when I choose to pick an item from it, i.e. a comboBox.Item, it returns the items from the first list. Yes, the first list, displaying the values from the filtered list; those values are class objects I'm packing into a dataGridView later on.
Here's the TextChanged:
private void textBox4_TextChanged_1(object sender, EventArgs e)
{
IEnumerable<artikal> filtered =
from artikal in art
where artikal.naziv.ToUpper().Contains(textBox4.Text.ToUpper()) || artikal.plu.Contains(textBox4.Text) || artikal.barkod.Contains(textBox4.Text)
select artikal;
comboBox1.DataSource = null;
comboBox1.Items.Clear();
List<artikal> filter = filtered.ToList<artikal>();
comboBox1.DataSource = filter;
and here's the class, I mean, if it's this important, but I'm not convinced it is:
public class artikal
{
public string plu { get; set; }
public string naziv { get; set; }
public string kolicina { get; set; }
public string nabavnaCena { get; set; }
public string prodajnaCnea { get; set; }
public string barkod { get; set; }
public override string ToString()
{
return plu + " " + naziv;
}
}
This art list is a global list defined above all else in the world. Here is how I populate the gridview:
public partial class NabavkaFrm : Form
{
#region some stuff lying here
List<item> art = new List<item>();
// other code
row.Cells[0].Value = art[comboBox1.SelectedIndex].plu;
row.Cells[1].Value = art[comboBox1.SelectedIndex].naziv;
}
So, yeah, any suggestions? And good time o' the day to everyone passing by :D

As I mentioned in the comment, the issue is not in the code where you filter the items. It cannot be. The issue is right here:
row.Cells[0].Value = art[comboBox1.SelectedIndex].plu;
row.Cells[1].Value = art[comboBox1.SelectedIndex].naziv;
and because art is the class level field, if the item from the combobox is 0, it will always show item at index 0 in art. You do not want this. You want to show item at index 0 from your filtered list but that list keeps changing. Sometimes item at index 0 is one thing, whilst another thing another time.
Do it like this instead:
var selectedItem = (comboBox1.SelectedValue as item);
row.Cells[0].Value = selectedItem.plu;

Related

Bind list to DataGridView not displaying anything and wiping out objects every time I click save

I am trying to bind a class list to a DataGridView on my WinForms application. Currently the bind code doesn't do anything. I have debugged through it and the source is correct contains the list with the correct item. But I don't see the rows in the DataGridView.
How do I display whats in the list onto my DataGridView? Also currently every time I click save it clears my class object, however I want to keep the previous values I put in the constructor. If there is already a country that exists I want a user pop up box to state whether they want to over write this or not - is this possible/ how can I best achieve this?
CountryWithDates.cs
class CountryWithDates
{
public string country;
public DateTime firstDate;
public DateTime furtherDate;
public DateTime rolldownDate;
public DateTime endDate;
}
On save click:
private void Save_Click(object sender, EventArgs e)
{
List<CountryWithDates> countryDates = new List<CountryWithDates>();
for (int i = 0; i < Countries_LB.Items.Count; i++)
{
if (Countries_LB.GetItemChecked(i))
{
countryDates.Add(new CountryWithDates(){country = Countries_LB.Items[i].ToString(),
firstMarkdownDate = DateTime.Parse(firstDatePicker.Text),
furtherMarkdownDate = DateTime.Parse(furtherDatePicker.Text),
rolldownMarkdownDate = DateTime.Parse(rolldownDatePicker.Text),
endMarkdownDate = DateTime.Parse(endMarkdownPicker.Text)});
}
}
//THIS DOESNT DO ANYTHING - I WANT TO BIND THE SOURCE TO THE GRIDVIEW but i dont see the output in the data gridview on the form when i click save
var bindingList = new BindingList<CountryWithDates>(countryDates);
var source = new BindingSource(bindingList, null);
gv_Countries.DataSource = source;
}
You should create public Porperties in your class and not public Fields:
class CountryWithDates
{
//Following the naming rule is good. I'll leave it to you.
public string country { get; set; }
public DateTime firstDate { get; set; }
public DateTime furtherDate { get; set; }
public DateTime rolldownDate { get; set; }
public DateTime endDate { get; set; }
public CountryWithDates() { }
public override string ToString()
{
return country;
}
}
This way you can bind a list of CountryWithDates objects to the CheckedListBox:
var lst = new List<CountryWithDates>();
//Add new objects ...
//lst.Add(new CountryWithDates { country = "Country 1", firstDate ... });
checkedListBox1.DataSource = null;
checkedListBox1.DataSource = lst;
To get and update the checked items from the list, create a new BindingSource, and bind it to the DataGridView, you just need to do:
checkedListBox1.CheckedItems
.Cast<CountryWithDates>()
.ToList()
.ForEach(item =>
{
item.firstDate = firstDatePicker.Value;
item.furtherDate = furtherDatePicker.Value;
item.rolldownDate = rolldownDatePicker.Value;
item.endDate = endMarkdownPicker.Value;
});
dataGridView1.DataSource = null;
var bs = new BindingSource(checkedListBox1.CheckedItems.Cast<CountryWithDates>(), null);
dataGridView1.DataSource = bs;
If I were doing this I would:
Add a new DataSet to my project
Open the DataSet designer
Add a DataTable, call it CountryWithDates, 6 columns (Country, First, Further, Markdown, End, SaveThisRow(boolean))
Save the DataSet
Open the form designer
Show the datasources window
Drag the node representing CountryWithDates onto the designer
DataGridView appears, as does dataset, bindingsource etc. Everything is bound already.
When time comes to save to disk and you only want to save those checked items, datatable.Copy() it, then delete every row that isn't marked for save, then call WriteXml to save the cleaned up copy. Perhaps something like this (untested):
private blah SaveButton_Click(blah){
var dt = (CountryWithDatesDataTable)_myDataset.CountryWithDates.Copy();
for(int i = dt.Count - 1; i >= 0; i--){
if(!dt[i].SaveThisRow)
dt[i].Delete(); //mark row deleted
}
dt.WriteXml(#"C:\temp\dt.xml")
}

Selected item in list box keeps returning null

i am trying to select a given number from my list box but when i run the code it returns null
i have tried .selectedvalue i have tried .selecteditem and .selecteditems
all return null
ID = ExpireditemInfo.GetItemText(ExpireditemInfo.SelectedItem);
ID is a string
This is my source i use dapper
loadinventory = iteminfo.GetExpireinfo(now,expirationDate);
ExpirationID.DataSource = loadinventory;
ExpirationID.DisplayMember = "Expireing_ID";
my data model
public string Transaction_ID { get; set; }
public string Type_Of_Transaction { get; set; }
public string Name { get; set; }
public string Quantity { get; set; }
public string Unit { get; set; }
public string Expireing_ID
{
get
{
return $"{Transaction_ID}";
}
}
i want to select the number 6 from the list-box etc and store that selection in a string which i will then convert to an int to pass along through a stored procedure. the int is for the id column of a database so it has to be an in when passing to the database.
is it that the 6 is not being recognized as a string and if so how do i select it?
i am trying to select a given number from my list box but when i run the code it returns null
After seeing the way you are binding to your ListBox, it seems you are not setting the ValueMember property, doing so you can have an actual DisplayMember and a ValueMember that represents the actual underlying value of that display object.
Here's what I would do, this is just one example:
// Holds the actual selected items value
public string ExpirationIDValue {get; private set;}
// Anytime the selected index changes, we update our property. You can
// put this on the constructor and or on load.
ExpirationID.SelectedIndexChanged += ExpirationID_SelectedIndexChanged;
// Event handler for when selection changes
private void ExpirationID_SelectedIndexChanged(object sender, EventArgs e)
{
if (sender is ListBox listBox && listBox.SelectedValue != null)
{
ExpirationIDValue = listBox.SelectedValue.ToString();
}
}
// This was for testing, just to get some data, you can ignore this
DataTable dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn("Expireing_ID",typeof(string)));
dataTable.Columns.Add(new DataColumn("Expireing_ID_Display",typeof(string)));
int i = 1;
while(i < 10)
{
dataTable.Rows.Add(i.ToString(),$"Display {i}");
i++;
}
// Here you need to make sure you set these properties to your actual
// property names.
ExpirationID.DataSource = dataTable;
ExpirationID.DisplayMember = "Expireing_ID_Display";
ExpirationID.ValueMember = "Expireing_ID";
Note: your selectedindexchanged event may fire early and cause an exception, what you can do is create a variable bool and on loading set it true and then in the event make sure that it's not true. At the end of loading the data, set that back to false.
Hopefully this will fix your issue, if there's something you don't understand or need further clarification, please let me know.
keycode: public string ExpirationIDValue { get; private set; }
private void ExpirationID_SelectedIndexChanged(object sender, EventArgs e)
{
**keycode:** ExpirationIDValue =ExpirationID.GetItemText(
ExpirationID.SelectedItem);
int ID;
ID = Convert.ToInt32(ExpirationIDValue);
loadinventory = iteminfo.ExpireitemInfo(ID);
ExpireditemInfo.DataSource = loadinventory;
ExpireditemInfo.DisplayMember = "Expireing_info";
}
Please note the valuemember was not necessary.

C# - WPF Entity Framework - Remove Selected Record from Database

In my C# / WPF application, I have a ListView control, which I populate as follows:
private void Load()
{
DbSet<recordHistory> recordHistory = _db.recordHistories;
var query = from cbHistory in recordHistory
orderby cbHistory.id descending
select new { cbHistory.id, cbHistory.Content, cbHistory.Size, cbHistory.DateAdded };
crRecordHistoryList.ItemsSource = query.ToList();
}
The above works as expected. My ListView control is populated with all the saved records from a SQL database.
When I start debugging the application, it executes as expected. However, when I select one of the ListView items (regardless of which item I select) and click on the Remove button, only the first record gets removed from the database and the ListView control.
Intended behavior is for the selected record to be removed from the database & the listview control...
My Remove method
private void Button_Remove_Click(object sender, RoutedEventArgs e)
{
foreach (var record in _db.recordHistories.Local.ToList())
{
Console.WriteLine("Removing Record Id:" + record.id);
_db.recordHistories.Remove(record);
}
_db.SaveChanges();
this.crRecordHistoryList.Items.Refresh();
this.Load();
}
Furthermore, all subsequent item selection and clicking on the remove button result in nothing being removed from database/listview control)
I have also tried the following (just to get the ID), within the Remove method:
Console.WriteLine("Removing Record Id:" + (crRecordHistoryList.SelectedItem as recordHistory).id);
in which case, I get:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
My recordHistory class (auto generated)
using System;
using System.Collections.Generic;
public partial class recordHistory
{
public int id { get; set; }
public string Content { get; set; }
public string Size { get; set; }
public Nullable<int> DateAdded { get; set; }
}
EDIT: I have figured out why it only removes the first record and then nothing else happens (no matter which item is selected)... it is because instead of getting the record from Local (in my foreach statement), I should simply have the following --- which was my initial attempt, trying to get the ID outputted to Console:
private void Button_Remove_Click(object sender, RoutedEventArgs e)
{
recordHistory testRecord = new recordHistory();
testRecord.id = (recordHistory)crRecordHistoryList.SelectedItem;
_db.recordHistories.Attach(testRecord);
_db.recordHistories.Remove(testRecord);
_db.SaveChanges();
this.crRecordHistoryList.Items.Refresh();
this.Load();
}
However, the following line
testRecord.id = (recordHistory)crRecordHistoryList.SelectedItem;
is throwing an error:
Cannot implicitly convert type 'recordHistory' to 'int'
By the way: the above would work perfectly, if I replace the 2nd line with: testRecord.id = 85; for example.
As such, I have tried changing the aforementioned line to the following, to no avail:
testRecord.id = System.Convert.ToInt32(crRecordHistoryList.SelectedItem);
Any ideas how I can remove the selected record?
Kudos to #pinkfloydx33 for pointing me in the right direction. Per his comment, I ventured onto further-research-rabbit-hole which eventually led to me creating a DTO class and modified my Load and Remove methods as follows--
Load method
private void Load()
{
List<HistoryRecordsDTO> records = (from record in _db.recordHistories
orderby record.id descending
select new HistoryRecordsDTO
{
id = record.id,
Content = record.Content,
Size = record.Size,
DateAdded = record.DateAdded
}).ToList();
crRecordHistoryList.ItemsSource = records;
}
Remove method
private void Button_Remove_Click(object sender, RoutedEventArgs e)
{
recordHistory record = new recordHistory();
record.id = (crRecordHistoryList.SelectedItem as HistoryRecordsDTO).id;
_db.recordHistories.Attach(record);
_db.recordHistories.Remove(record);
_db.SaveChanges();
this.crRecordHistoryList.Items.Refresh();
this.Load();
}
And, my DTO class - HistoryRecordsDTO
public class HistoryRecordsDTO
{
public int id { get; set; }
public string Content { get; set; }
public string Size { get; set; }
public Nullable<int> DateAdded { get; set; }
}
Doing the above solved my problem of removing a selected ListView item.
As being a C#/WPF newbie, I am certain that there are much nicer/optimal/better in general ways to do this... I look forward to other answers and learn from it.

Implementing a find system for a ListView in C#

I am creating an application in C# using a ListView control that lets you create lists. I am implementing a Find function using the Find() method. Here’s my code:
if (findTextBox.Text != "")
{
ListViewItem[] lviFoundList = listItemsList.Items.Find(findTextBox.Text, true);
amountFound.Text = "Found " + Convert.ToString(lviFoundList.Count());
if (lviFoundList.Count() != 0)
{
int firstItemIndex = lviFoundList[0].Index;
listItemsList.Items[firstItemIndex].Selected = true;
}
}
else
{
amountFound.Text = "Found 0";
}
However, it doesn’t return any matches. What am I doing wrong?
Find method requires your listView item's Name, did you set your list view item's name property? If you want to search for text you can use this:
var lviFoundList = new List<ListViewItem>();
foreach(var item in listItemsList.Items)
{
if(item.Text == findTextBox.Text) lviFoundList.Add(item);
}
The Find() Method looks at the ListViewItem's name, not it's text.
You want this instead:
if (findTextBox.Text != "")
{
List<ListViewItem> items = new List<ListViewItems>();
foreach ListViewItem lvi in listItemsList.Items
{
if (lvi.Text == findTextBox.Text)
items.Add(lvi);
}
amountFound.Text = "Found " + Convert.ToString(lviFoundList.Count());
if(lviFoundList.Count() != 0)
{
int firstItemIndex = lviFoundList[0].Index;
listItemsList.Items[firstItemIndex].Selected = true;
}
}
else
{
amountFound.Text = "Found 0";
}
Honestly, the ListView.Find() method is rather poor and it's much easier to roll your own with LINQ. Think about what Find really is trying to accomplish -- a specific filtering, typically one record.
The first step, if you haven't already, would be to keep a cached collection of your data objects. Let's assume you have a list of Person classes like so:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string JobTitle { get; set; }
public DateTime DateOfBirth { get; set; }
}
Then in your MainForm you have a ListView and a member variable people defined as a List<Person>. Your ListView.Items should reflect the contents of this List<Person>.
So now maybe you want to find a person based on their FirstName or LastName, right? You could use LINQ in a function like so:
int FindFirstIndexOfPersonNamed(string firstOrLastName)
{
// WARNING: This is case sensitive!
return people.FindIndex(p => p.FirstName.Contains(firstOrLastName) || p.LastName.Contains(firstOrLastName));
}
Since your ListView.Items should be reflecting your List<Person> the index should be identical:
// Get the found item and do whatever you want with it...
var selectedListViewItem = listView.Items[index];

Problem in binding a listbox to data

I have a table that have these fields: ID , Name
I have bound a listbox to the table.
My question is, when the user has selected an item in listbox, how would I find out what the ID of the selected item is?
Note: The id is not equal to the selectedindex or id of items in items list
e.g.
Suppose you have a DataTable dt, with columns ID and Name in it.
then while binding include the following code,
this.listbox.DataSource = dt;
this.listbox.DisplayMember = "Name";
this.listbox.ValueMember = "ID";
while reading the selected values of listbox,
this.listbox.SelectedItem will give u the selected Name and
this.listbox.SelectedValue will give u the corresponding ID
test it
lst.SelectedItem.Value;
OR
lst.SelectedValue;
where lst is a ListBox Cotrol
What type of application is this? ASP.net, Windows Forms, WPF?
I have a feeling you are working with Windows Forms, as the other two are much clearer...
Here is some code for a Windows Forms App... Basically, you create your own class, and use that for the list items. The list box will display the results of the ToString() method, so override that to get the value you wanna display. When you access ListBox.SelectedItem, it will be an instance of the class you defined, and you can access whatever properties are necessary:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MyListItem item1 = new MyListItem("Java", 1);
MyListItem item2 = new MyListItem("C#", 221);
MyListItem item3 = new MyListItem("C++", 13);
listBox1.Items.Add(item1);
listBox1.Items.Add(item2);
listBox1.Items.Add(item3);
}
private class MyListItem
{
public string ItemName { get; set; }
public int ItemId { get; set; }
public MyListItem(string name, int id)
{
this.ItemName = name;
this.ItemId = id;
}
public override string ToString()
{
return this.ItemName;
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
MyListItem selectedItem = (MyListItem)listBox1.SelectedItem;
MessageBox.Show(string.Format("Name is: {0}, Id is: {1}", selectedItem.ItemName, selectedItem.ItemId));
}
}

Categories