How to remove more items from combobox? - c#

I am trying to remove more items from a combobox but the application is only removing one item at a time.
The combobox has a list of email addresses. I want to remove empty items (""), and those that don't have # inside of text.
Code below only removes one item at a time.
for (int i = 0; i < cmbTo.Items.Count; i++)
{
string st = cmbTo.Items[i].ToString();
if (st == "" || st.IndexOf("#") == -1)
{
cmbTo.Items.RemoveAt(i);
}
}
How can I rewrite this?

Hint: Think about what happens to the i variable when you remove an item
...
When you RemoveAt an item, the item is removed, and every subsequent item moves up one index. Your loop then hits the bottom, where it goes back to the top, increments i, and moves on.
Result? You just skipped an item. If this is the last item in the list, then the loop exists.
Instead, manually decrement i to offset your removal, so that everything works:
for (int i = 0; i < cmbTo.Items.Count; i++)
{
string st = cmbTo.Items[i].ToString();
if (st == "" || st.IndexOf("#") == -1)
{
cmbTo.Items.RemoveAt(i);
i--;
}
}

Your code doesn't work because the moment you remove an item from the collection, the Count() decreases and the for loop exits before going through all the list of items.
You need to first create a list of elements to remove (put them in a temp list) and then iterate through the newly created list calling cmbTo.Items.Remove(currentElement);

When you remove an item from a combobox, the indices of the following items change and your item count will change. Could that account for the behavior you're seeing?

Just do the removal in the opposite direction (i.e. from the end to the front), and you won't need to worry about adjusting i1 when the item is removed:
var items = cmbTo.Items;
int i = items.Count;
while (i > 0) {
--i;
string st = items[i].ToString();
if (st == "" || st.IndexOf("#") < 0)
items.RemoveAt(i);
}
1 Which you currently don't do, so some items that should potentially be removed are skipped, which causes your problem.

Related

C# for loop skipping last item

I have the below for loop
int listCount = _itemCollection.Count;
//_itemCollection is of type SPListItemCollection
for (int i=0;i<listCount;i++)
{
var item = _itemCollection[i]; // just to prevent changes in all places inside the for loop
if(item['expirydate']>today){
item.delete();
listCount--; //as I am removing 1 item, I am decrementing count
}
}
In this for loop, I am iterating through the items in itemcollection and deleting some of them. i.e item will be removed from itemcollection array and so itemcollection.count will be reduced by 1
This is not deleting the 3rd item every time, when I have 3 items to delete
I am not sure what condition should be used for getting it right
You should go in the reverse order as below and use for instead of foreach as below.
int listCount = _itemCollection.Count;
for (int i = listCount - 1; i >= 0; i--)
{
var item = _itemCollection[i]; // just to prevent changes in all places inside the for loop
if(item['expirydate'] > today){
item.delete();
}
}
You can do something like this:
_itemCollection.RemoveAll(item => item['expirydate'] > today);
This removes all the items that matches the given condition.
To remove item from SPListItemCollection check this documentation
Try this:
int listCount = _itemCollection.Count;
for (int i = 0; i < listCount; i++)
{
var item = _itemCollection[i];
if(item [expirydate] > today)
{
_itemCollection.Remove(item);
listCount--;
}
}
This may fulfill your want. Here you can directly use _itemCollection[i] instead of item.
I hope this may help you. Enjoy coding.

C#: How do I iterate through two listBoxes individually?

I am trying to iterate through two listBoxes for a program I am coding. Both listBoxes will have a different item count inside of it.
Basically, I want my program to get the selectedItem from one listBox and use the string or text from that item to replace the text from EACH and EVERY single item in the other listBox.
Once it's done using the selectedItem from the original listBox for all the items in the other listBox, I want it to go to the next item in the original listBox and do the same process all over again.
It should repeat this UNTIL it has gone through ALL of the items in the original listBox.
Hopefully that made sense....
Here is some example code I made. I created two for loops so that it could iterate through both listBoxes.
for (int i = 0; i < listBoxOriginal.Items.Count; i++)
{
string linkurl = listBoxOriginal.Items[i].ToString() + "..";
listBoxNewListBox.SelectedIndex = 0;
for (int o = 0; o < listBoxNewListBox.Items.Count; o++)
{
string s = listBoxNewListBox.Items[o] as string;
string newurl = s.Replace("DOMAIN", linkurl);
listBoxNewListBox.SelectedIndex++;
}
}
My issue is, when the inner for loop finishes iterating completely it errors out. I know the error is because it reached the end of the listBox and can't go any further, but I don't know how else to iterate through the listBox without having the items selected.
What it should do is, once it reaches the end of "listBoxNewListBox" it should go to the next item in "listBoxOriginal", and perform the same process all over again until it's done going through every item in "listBoxOriginal".
Any help would be appreciated!
I think problem is because of SelectedIndex at list. I think it's just going to far.
Here is a little modification:
for (int i = 0; i < listBoxOriginal.Items.Count; i++)
{
string linkurl = listBoxOriginal.Items[i].ToString() + "..";
for (int o = 0; o < listBoxNewListBox.Items.Count; o++)
{
string s = listBoxNewListBox.Items[o] as string;
string newurl = s.Replace("DOMAIN", linkurl);
listBoxNewListBox.SelectedIndex = o;
}
}
Here is explanation:
When in inner loop you are doing this operation: listBoxNewListBox.SelectedIndex++ you are setting this index as 1 more than index of loop. That means, if we look at very last iteration of inner loop, this index is set with value which is already to high. This is probably reason why application throws an exception.

Clearing Multi-Selected Items From Listbox C#

What i've tried:
try 1:
for(int x = listBox1.SelectedIndices.Count - 1; x>= 0; x--)
{
int idx = listBox1.SelectedIndices[x];
listBox2.Items.Add(listBox1.Items[idx]);
listBox1.Items.RemoveAt(idx);
}
try 2:
ArrayList tmpArr = new ArrayList();
foreach (object obj in listBox1.SelectedItems)
{
listBox2.Items.Add(obj);
tmpArr.Add(obj);
}
foreach (object obj in tmpArr.ToArray())
{
listBox1.Items.Remove(obj);
}
Also tried everything in the following post: How to remove multiple selected items in ListBox?
Still nothing worked. What am I doing wrong?
var selectedItems = new object[listBox1.SelectedItems.Count];
listBox1.SelectedItems.CopyTo(selectedItems, 0);
foreach (var item in selectedItems)
{
listBox1.Items.Remove(item);
}
or with a bit of LINQ to simplify the code:
foreach (var item in listBox1.SelectedItems.Cast<object>().ToArray())
{
listBox1.Items.Remove(item);
}
The reasoning here is that you get all the selected items and put them into another list first. The original issue is that any change you make to the ListBox will change things like SelectedItems and SelectedIndices. Once you've created an independent array and put the selected items into it, nothing you do to the ListBox will affect that array so you can just enumerate it normally.
listbox1.BeginUpdate();
for (int x = listBox1.SelectedIndices.Count - 1; x >= 0; x--)
{
int idx = listBox1.SelectedIndices[x];
listBox1.Items.RemoveAt(idx);
}
listbox1.EndUpdate();
If you cannot guarantee that every object in the list is unique, then this is the correct way to do it, to ensure that the correct selected items get removed.
If you have multiples of the same object in your listbox, you have to refer to them by "index", otherwise if you remove them by "item" it will remove the first instance of any matching items it finds.
I am in the process of writing a bus route planner which called for replication of the waypoint markers in the list. These were stored as strings, so for example I might have had "w1", "w2", "w3"... "w2" (think of a bus going down a high street, looping round a couple of blocks and then returning down the other side to understand why I have that... I only need waypoint markers in the centre of the road, not in each lane)
If I had selected the last "w2" marker as part of a range and used the selectedItem() method to to remove them, it would have removed the first "w2", not the second one. By using the SelectedIndex() method, it removes based on position, not value, so duplicate values are left safely intact.
I just wanted to add that as I have just been dealing with this very same problem, so saw first hand the problem removing by SelectedItem() caused.

Switch statement inside a foreach loop - not getting expected results

So I am trying to loop though items that are in a listbox in my application. The list box will allow you to select multiple items to which I have a method tied to each item in the listbox. I have a counter variable incremented each time the loop works.When I use the foreach loop with the switch statement below, it does the first item correct, but then loops through the same item again. I know I am missing something as it is supposed to go to the next item in the listbox and not the same item.
string reportname = lstbxReports.SelectedValue.ToString();
int i = 0;
foreach (var report in reportname)
{
switch (reportname)
{
case "Overview":
{
if (i < 1)
{
PrintOverview(filename);
}
else if (i >= 1)
{
PrintOverviewAppend(filename);
}
break;
}
case "Sources":
{
if (i < 1)
{
PrintSource(filename);
}
else if (i >= 1)
{
PrintSourceAppend(filename);
}
break;
}
}
i++
Any thoughts or suggestions on how I can get the foreach loop to go to the next item in the selected listbox?
Also, this is just a snippet as I have about 11 case items to loop through.
You probably want to switch on report, not reportname.
foreach(string item in listBox.Items)
{
}
?
Depends on how you setup the data source for the listbox though (I'm assuming this is WinForm?). If you created it by adding .Items or using the designer then this will work. However if you've used .DataSource then it wont work.
I'd personally have a
List<string> list = SomeMethodWhereIMakeTheList();
and set that to:
listbox.DataSource = list;
then I wouldn't even have to touch the ListBox to mess with the contents:
list.ForEach(...)
Don't do the print logic in a foreach. Split out the data then print such this (note I changed the name of reportname to reportnames to signify a list of items)
string reportnames = lstbxReports.SelectedValue.ToString();
var firstReport = reportnames.First(); // No error checking here, would use FirstOrDefault with null checks.
if (firstReport == "OverView")
PrintOverview(filename);
else
PrintSource(filename);
// Now print out the rest
reportnames.Skip(1)
.ToList()
.ForEach(rp =>
{
if (rp == "OverView")
PrintOverviewAppend(filename);
else
PrintSourceAppend(filename);
});

Remove selected rows from multi-column listView

I have a listview with two columns and I'm using a context menu to allow users to remove selected rows. To remove the selected rows, I've tried with the following code but it doesn't work:
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
listView1.SelectedItems.Clear();
}
I suspect this is because the listview has two columns, but I can't figure out a solution to remove selected rows. Removing all rows works with: listView1.Items.Clear();.
The latest example of BeefTurkey looks correct, but he should decrement the variable i after removing a selected item:
for (int i = 0; i < listView1.Items.Count; i++ )
{
if (listView1.Items[i].Selected)
{
listView1.Items[i].Remove();
i--;
}
}
The index of items larger as i is decremented by 1 after the removal. So you should reposition i to match the next not tested item.
while (listBox1.SelectedItems.Count > 0)
{
listBox1.Items.Remove(listBox1.SelectedItem);
}
foreach(ListViewItem lvItem in lvDocument.SelectedItems)
{
lvDocument.Items.Remove(lvItem);
}
This seems to work:
for (int i = 0; i < listView1.Items.Count; i++ )
{
if (listView1.Items[i].Selected)
{
listView1.Items[i].SubItems.Clear();
}
}
Is there any way to remove items and re-order the listView so that there are no empty rows in the middle of other rows?
This seems to be a better solution:
for (int i = 0; i < listView1.Items.Count; i++ )
{
if (listView1.Items[i].Selected)
{
listView1.Items[i].Remove();
}
}
What you can do:
foreach (ListViewItem Item in LstvClients.Items)
{
if (item.Selected)
{
LstvClients.Items.Remove(Item);
}
}
(Yours is better, item.Remove())
I have been using something slightly different then the others to remove all the selected items from a ListView control:
foreach (ListViewItem listViewItem in listView1.SelectedItems)
{
listView1.Items.Remove(listViewItem);
}
I'm not sure how this would match up performance-wise to the other posted methods on large lists, but I think it is a little cleaner looking in cases where that isn't an issue.
This is the correct way to remove all selected items. The method is to always access fist selected item with an index 0 and loop until no more selected items left. You cannot refer to other items inside collection with an absolute index safely since indexes will change as soon as you delete one of the items.
while( listView1.SelectedItems.Count > 0)
{
listView1.Items.Remove(lvFiles.SelectedItems[0]);
}
do
{
this.listView1.CheckedItems[0].Remove();
} while (this.listView1.CheckedItems.Count > 0);
This works better

Categories