I am trying to remove numerical items from a ListBox if those values exist in another ListBox. My code does not seem to work and I could not locate any help online. ListBox1 is populated by Array and ListBox2 is populated from a DataSet table (fyi).
Also for reference: I'm not adding and items to a listbox or selecting...simply just want to compare both and remove ListBox2 items from ListBox1 if they exist all automatically with a press of a button. Thank you,
private void button1_Click(object sender, EventArgs e)
{
foreach (int item in listBox1.Items)
{
if (listBox2.Items.Contains(item))
{
listBox1.Items.Remove(item);
}
}
}
Well you're only referencing one list box in your code - I suspect you would want:
private void button1_Click(object sender, EventArgs e) {
foreach (int item in listBox1.Items)
{
if (listBox2.Items.Contains(item)) // notice change of reference
{
listBox1.Items.Remove(item);
}
}
However that would cause an error since you're modifying the ListBox while you're iterating over it's items. One way to safely remove items it to iterate backwards over the colection:
for (int i = listBox1.Items.Count - 1; i >= 0; i--)
{
int item = listBox1.Items[i];
if (listBox2.Items.Contains(item)) // notice change of reference
{
listBox1.Items.RemoveAt(i);
}
}
#D Stanley
Thank you for your help and explanation. #Yuriy - Thank you for the clarification, the
i >= 0
works great. I also converted to listbox to int32. Below is the fully working code:
private void button1_Click(object sender, EventArgs e)
{
for (int i = listBox1.Items.Count - 1; i>= 0; i--)
{
int item = Convert.ToInt32(listBox1.Items[i]);
if (listBox2.Items.Contains(item))
{
listBox1.Items.Remove(item);
}
}
}
Related
See I have a HashSet with several values, this values can contain for example numbers like 4141234567, 4241234567, 4261234567 and so on. I put a radioButton1 in my UserControl and I want when I click this just the numbers with 414 and 424 remains on my ListBox, for that I wrote this code:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
var bdHashSet = new HashSet<string>(bd);
if (openFileDialog1.FileName.ToString() != "")
{
foreach (var item in bdHashSet)
{
if (item.Substring(1, 3) != "414" || item.Substring(1, 3) != "424")
{
listBox1.Items.Remove(item);
}
}
}
}
But when I run the code I get this error:
Items collection cannot be modified when the DataSource property is set.
What is the proper way to remove the non wanted items from the list without remove them from the HashSet? I'll add later a optionButton for numbers that begin with 0416 and 0426 and also a optionButton to fill the listBox with original values, any advice?
try
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
var bdHashSet = new HashSet<string>(bd);
listBox1.Datasource = null;
listBox1.Datasource = bdHashSet.Where(s => (s.StartsWith("414") || s.StartsWith("424"))).ToList();
}
Try this:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
var bdHashSet = new HashSet<string>(bd);
listBox1.Datasource = bdHashSet.Select(s => (s.Substring(1, 3) == "414" || s.Substring(1, 3) == "424"));
//After setting the data source, you need to bind the data
listBox1.DataBind();
}
I think that you can select the elements with linq and then reassign the listBox with the result. In that way you dont need to remove elements from the list and you can keep the elements of the HashSet.
You can use BindingSource object. Bind it with DataSource and then use the RemoveAt() method.
Try this :
DataRow dr = ((DataRowView)listBox1.SelectedItem).Row;
((DataTable)listBox1.DataSource).Rows.Remove(dr);
I'm having some problem to get the index of the selected row in a listview. I wonder why this code isn't working? I get a red line below the SelectedIndex
private void lvRegAnimals_SelectedIndexChanged(object sender, EventArgs e)
{
int index = lvRegAnimals.SelectedIndex;
string specialData = motelManager.GetInfoFromList(index);
UppdateSpecialData(specialData);
}
Help is preciated. Thanks!
EDIT:
For some strange reason I get two messages when I click on one of the lines in the listView!? First I get the previous number and then the number for the last clicked line. What could be wrong?
private void lvRegAnimals_SelectedIndexChanged(object sender, EventArgs e)
{
int index = lvRegAnimals.FocusedItem.Index;
MessageBox.Show(Convert.ToString(index));
}
It's working now when I added a check like this:
if(lvRegAnimals.SelectedIndices.Count > 0)
Because ListView doesn't contain any SelectedIndex, instead there is a property of SelectedIndices.
var indices = lvRegAnimals.SelectedIndices;
//indices[0] you can use that to access the first selected index
ListView.SelectedIndices
When the MultiSelect property is set to true, this property returns a
collection containing the indexes of all items that are selected in
the ListView. For a single-selection ListView, this property returns a
collection containing a single element containing the index of the
only selected item in the ListView.
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
// Acquire SelectedItems reference.
var selectedItems = listView1.SelectedItems;
if (selectedItems.Count > 0)
{
// Display text of first item selected.
this.Text = selectedItems[0].Text;
}
else
{
// Display default string.
this.Text = "Empty";
}
}
Try :
listView1.FocusedItem.Index
This give you the index of the selected row.
There is another thread like this one, but here it goes again.
It can return NULL. Also the SelectedIndexChanged event can be FIRED TWICE. And the first time, there nothing selected yet.
So the only safe way to find it is like this:
private void lv1_SelectedIndexChanged(object sender, EventArgs e)
{
if (lv1.FocusedItem == null) return;
int p = lv1.FocusedItem.Index;
... now int p has the correct value...
The ListView is a darn hassle to work with sometimes.
A simple solution i've used is a for loop that checks for the
selected Item.
I've put my solution in the "When index change trigger" within the ListView.
Example:
int sel_item = 0; //an int to store the selected item index.
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Selected == true)
{
sel_item = i;
}
}
}
This would ofcourse only work correctly with the "Multiselection" option set as false.
I need to pass a checkeditem of a checklistbox while firing an event from a dynamic checklistbox. The code snippet is provided below with comments...
I'm facing an issue with the same piece of code. On mouse double click event its throwing an exception saying IndexoutofRange. Its working fine with the index value 0.Please help 2 solve me both.
private void clbTables_MouseDoubleClick(object sender, MouseEventArgs e)
{
int indexofselectedtable;
indexofselectedtable = Convert.ToInt32(clbTables.SelectedIndex);
if (clbTables.CheckedItems.Count != 0)
{
Metadata metadataobj = new Metadata(dbProperties);
DBList = metadataobj.GetColumns(clbTables.CheckedItems[indexofselectedtable].ToString()); // This throws an error on checking an item of index>0.
for (int j = 0; j < DBList.Count; j++)
{
chklistcolumns.Name = "chklist" + j++;
chklistcolumns.Items.Add(DBList.ElementAt(j));
}
this.Controls.Add(chklistcolumns);
chklistcolumns.ItemCheck += new ItemCheckEventHandler(OnCheckListBoxItemCheck);
}
}
private void OnCheckListBoxItemCheck(object sender, ItemCheckEventArgs args) //need to pass the tablename which can be got from the object clbTables
{
Columns columnobj = new Columns();
columnobj.ColumnName = this.Text;
columnobj.Id = this.Name;
columnobj.TableName= // need to get the tablename from the object clbtables
}
I think I see what the issue here is, you are trying to match the selected index of your CheckedListBox with an index in the CheckedItems collection, but it doesn't work that way.
Consider this: you have 10 items in your CheckedListBox, and three of them are checked. That gives you .Items[10] and .CheckedItems[3]. If then you double click on the 7th item in the CheckedListBox, your SelectedIndex will be 6, but there will only be three items in the CheckedItems collection. So when you try to read clbTables.CheckedItems[6] you are going to be outside of the range of that collection.
clbTables.CheckedItems is another collection. You can't use clbTables.SelectedIndex in it.
Why not just to use SelectedValue property?
I have a WPF window that manages sets of configurations and it allows users to edit a configuration set (edit button) and to remove a configuration set (remove button). The window has a ListBox control that lists the configuration sets by name and its ItemsSource has a binding set to a list of configuration sets.
I'm trying to remove the item in the code behind file for the window..
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
var removedItems = configSetListBox.SelectedItems;
foreach(ConfigSet removedItem in removedItems)
{
configSetListBox.Items.Remove(removedItem);
}
}
My code yields an invalid operation exception stating "Access and modify elements with ItemsControl.ItemsSource instead." What property should I be accessing to properlyremove items from the ListBox? Or is there possibly a more elegant way to handle this in WPF? My implementation is a bit WinForm-ish if you will :)
Solution
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
foreach(ConfigSet removedItem in configSetListBox.SelectedItems)
{
(configSetListBox.ItemsSource as List<ConfigSet>).Remove(removedItem);
}
configSetListBox.Items.Refresh();
}
In my case I had a List as the ItemSource binding type so I had to cast it that way. Without refreshing the Items collection, the ListBox doesn't update; so that was necessary for my solution.
use:
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
foreach(ConfigSet item in this.configSetListBox.SelectedItems)
{
this.configSetListBox.ItemsSource.Remove(item); // ASSUMING your ItemsSource collection has a Remove() method
}
}
Note: my use of this. is just so it as it is more explicit - it also helps one see the object is in the class namespace as opposed to variable in the method we are in - though it is obvious here.
This is because , you are modifying a collection while iterating over it.
if you have binded item source of listbox than try to remove the items from the source
this was answered here already.
WPF - Best way to remove an item from the ItemsSource
You will need to implement an ObservableCollection and then whatever you do to it will be reflected in your listbox.
I Used this logic to preceed. And it worked.
you may want to try it.
private void RemoveSelectedButton_Click(object sender, RoutedEventArgs e) {
if (SelectedSpritesListBox.Items.Count <= 0) return;
ListBoxItem[] temp = new ListBoxItem[SelectedSpritesListBox.SelectedItems.Count];
SelectedSpritesListBox.SelectedItems.CopyTo(temp, 0);
for (int i = 0; i < temp.Length; i++) {
SelectedSpritesListBox.Items.Remove(temp[i]);
}
}
for (int i = lstAttachments.SelectedItems.Count - 1; i >= 0; i--)
{
lstAttachments.Items.Remove(lstAttachments.SelectedItems[i]);
}
Simplest way to remove items from a list you iterate through is going backwards because it does not affect the index of items you are moving next to.
I created two RadioButton (Weight and Height). I will do switch between the two categories. But the they share the same ListBox Controllers (listBox1 and listBox2).
Is there any good method to clear all the ListBox items simpler? I didn't find the removeAll() for ListBox. I don't like my complex multi-lines style which I posted here.
private void Weight_Click(object sender, RoutedEventArgs e)
{
// switch between the radioButton "Weith" and "Height"
// Clear all the items first
listBox1.Items.Remove("foot");
listBox1.Items.Remove("inch");
listBox1.Items.Remove("meter");
listBox2.Items.Remove("foot");
listBox2.Items.Remove("inch");
listBox2.Items.Remove("meter");
// Add source units items for listBox1
listBox1.Items.Add("kilogram");
listBox1.Items.Add("pound");
// Add target units items for listBox2
listBox2.Items.Add("kilogram");
listBox2.Items.Add("pound");
}
private void Height_Click(object sender, RoutedEventArgs e)
{
// switch between the radioButton "Weith" and "Height"
// Clear all the items first
listBox1.Items.Remove("kilogram");
listBox1.Items.Remove("pound");
listBox2.Items.Remove("kilogram");
listBox2.Items.Remove("pound");
// Add source units items for listBox1
listBox1.Items.Add("foot");
listBox1.Items.Add("inch");
listBox1.Items.Add("meter");
// Add target units items for listBox2
listBox2.Items.Add("foot");
listBox2.Items.Add("inch");
listBox2.Items.Add("meter");
}
isn't the same as the Winform and Webform way?
listBox1.Items.Clear();
I think it would be better to actually bind your listBoxes to a datasource, since it looks like you are adding the same elements to each listbox. A simple example would be something like this:
private List<String> _weight = new List<string>() { "kilogram", "pound" };
private List<String> _height = new List<string>() { "foot", "inch", "meter" };
public Window1()
{
InitializeComponent();
}
private void Weight_Click(object sender, RoutedEventArgs e)
{
listBox1.ItemsSource = _weight;
listBox2.ItemsSource = _weight;
}
private void Height_Click(object sender, RoutedEventArgs e)
{
listBox1.ItemsSource = _height;
listBox2.ItemsSource = _height;
}
Write the following code in the .cs file:
ListBox.Items.Clear();
while (listBox1.Items.Count > 0){
listBox1.Items.Remove(0);
}
You should be able to use the Clear() method.
I made on this way, and work properly to me:
if (listview1.Items.Count > 0)
{
for (int a = listview1.Items.Count -1; a > 0 ; a--)
{
listview1.Items.RemoveAt(a);
}
listview1.Refresh();
}
Explaining: using "Clear()" erases only the items, do not
removes then from object, using RemoveAt() to removing an item of beginning position
just realocate the others [if u remove item[0], item[1] turns into [0] triggering a new internal event],
so removing from the ending no affect de others position,
its a Stack behavior, this way we can Stack over all items, reseting the object.
VB
ListBox2.DataSource = Nothing
C#
ListBox2.DataSource = null;