How do I setup a button click to remove only null contents from a listbox and keep the listbox populated.
Example:
Work
Files
here
Armor
Result (on_button_click,changes listbox):
Work
Files
here
Armor
Any help always appricated.
You need to loop backwards through the items in the ListBox and remove the items that you don't like.
For example:
for (int i = listBox.Items.Count - 1; i >= 0; i--) {
if (String.IsNullOrEmpty(listBox.Items[i] as String))
listBox.Items.RemoveAt(i);
}
The loop needs to be backwards because otherwise, all of the upcoming indices will move down.
Maybe something like this?
Whoops, as noted, you cannot iterate through a collection and modify it at the same time. Therefore, I present some Frankenstein code:
private void OnButtonClick(object sender, EventArgs e)
{
List<String> removeMe = new List<String>();
foreach(String x in listBox.Items)
{
if (String.IsNullOrEmpty(x))
{
removeMe.Add(x);
}
}
foreach(String x in removeMe)
{
listBox.Items.Remove(x);
}
}
Related
So I have created a button that when pressed it deletes the multiple items in the listview. However, I can only seem to make it delete one list item at a time. I know this is badly worded so my code should help explain what I am doing:
private void button2_Click(object sender, EventArgs e) //remove
{
try
{
foreach ( ListViewItem eachItem in listView1.SelectedItems)
{
listView1.Items.Remove(eachItem);
}
task.RemoveAt(listView1.SelectedItems[0].Index); // Remove task from the list "task"
I am trying to make it delete all selected items from my listview as well as my list named "task" However, the line of code above only allows me to delete one selected item from the list at a time.
Any help? Thanks
Try This,
for (int i = task.SelectedItems.Count - 1; i >= 0; i++)
{
if (task.Items[i].Selected)
{
task.Items.Remove(listView2.Items[i]);
}
}
I'm going to assume that your list of tasks is equal, in item count, to your ListView, and that the object in task[0] is the same as ListView.Items[0]. If that is true, remove the item from the task first then remove the item from the ListView
// Removing items from the bottom of the selected items and working your way up
for (int i = listView1.SelectedIndices.Count - 1; i >= 0; i--)
{
task.RemoveAt(listView1.SelectedIndices[i]);
listView1.Items.RemoveAt(listView1.SelectedIndices[i];
}
foreach (ListViewItem eachItem in listView1.Items)
{
listView1.Items.Remove(eachItem);
}
you can only remove one item per line,
you can use the ".ToArray" extension method, if you are enumerating over a changing enumerable.
you should also use the BeginUpdate / EndUpdate function, to speed it up
https://msdn.microsoft.com/library/system.windows.forms.listview.beginupdate%28v=vs.110%29.aspx
I am attempting to save items from a listbox to a file; I have tried using things like
listbox.items
listbox.items.addrange
listbox.items.count
listbox.items.text (which doesn't give me an error but it also doesn't save)
Here is code:
private void button2_Click(object sender, EventArgs e)
{
if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
File.WriteAllText(saveFileDialog1.FileName, listBox1.Items.Count);
}
}
File.WriteAllText expects two items: a filepath, and the string to write (as a String):
You gave it:
ListBox.Items (a collection)
ListBox.Items.AddRange (a function)
ListBox.Items.Count (Valid, but not related to the actual items because it is just the count)
ListBox.Items.Text (what????) (this probably doesn't compile, as I'm not aware of that property)
You need to iterate through all the items, joining them all if you really want to use File.WriteAllText.
Something like:
File.WriteAllText(saveFileDialog1.FileName, String.Join(",", listBox1.Items));
//If the above doesn't do the cast implicitly, and its always better to be explicit!
File.WriteAllText(saveFileDialog1.FileName, String.Join(",", listBox1.Items.Cast<string>()));
String.Join
There are lots of other ways to generate the output of course, but the short of it is that you need to iterate each element in the Items collection and write it out to the file individually, or use a function like String.Join to do it all in one go.
You could loop through the items and create a string that contains all of them, then write that string to the file.
string itemString = "";
foreach (Item item in listbox1.Items)
{
itemString+=item.Text;
}
File.WriteAllText(saveFileDialog1.FileName, itemString);
You would probably want to add some sort of delimiter with each item, a comma, or a newline character or something so the file doesn't look like gibberish.
To save the items from listBox:
private void SaveItems()
{
using(StreamWriter sw = new StreamWriter("file.txt"))
{
for (int i = 0; i < listBox1.Items.Count; i++)
{
sw.WriteLine(listBox1.Items[i]);
}
}
}
To load the items to listBox:
private void LoadItems()
{
using(StreamReader sr = new StreamReader("file.txt"))
{
while (!sr.EndOfStream)
{
listBox1.Items.Add(sr.ReadLine());
}
}
}
If you want to store every item in a ListBox into a file, it would be best to use File.WriteAllLines(String, String[]).
File.WriteAllLines(saveFileDialog1.FileName,
listBox1.Items.OfType<ListViewItem>().Select(i => i.Text).ToArray());
I have the MultiSelect property of the listView set to false and I'm trying to get a single listViewItem. But the available property is SelectedItems. I've been using the following code...
foreach (ListViewItem item in listView1.SelectedItems)
{
//do something with item.text or whatever
}
Because I know there will only be one item selected. What is the correct way of doing this?
Usually SelectedItems returns either a collection, an array or an IQueryable.
Either way you can access items via the index as with an array:
String text = listView1.SelectedItems[0].Text;
By the way, you can save an item you want to look at into a variable, and check its structure in the locals after setting a breakpoint.
I do this like that:
if (listView1.SelectedItems.Count > 0)
{
var item = listView1.SelectedItems[0];
//rest of your logic
}
Sometimes using only the line below throws me an Exception,
String text = listView1.SelectedItems[0].Text;
so I use this code below:
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedIndices.Count <= 0)
{
return;
}
int intselectedindex = listView1.SelectedIndices[0];
if (intselectedindex >= 0)
{
String text = listView1.Items[intselectedindex].Text;
//do something
//MessageBox.Show(listView1.Items[intselectedindex].Text);
}
}
If its just a natty little app with one or two ListViews I normally just create a little helper property:
private ListViewItem SelectedItem { get { return (listView1.SelectedItems.Count > 0 ? listView1.SelectedItems[0] : null); } }
If I have loads, then move it out to a helper class:
internal static class ListViewEx
{
internal static ListViewItem GetSelectedItem(this ListView listView1)
{
return (listView1.SelectedItems.Count > 0 ? listView1.SelectedItems[0] : null);
}
}
so:
ListViewItem item = lstFixtures.GetSelectedItem();
The ListView interface is a bit rubbish so I normally find the helper class grows quite quickly.
For a shopping cart situation here's what I recommend. I'm gonna break it down into it's simplest form.
Assuming we start with this(a list view with 2 colums, 2 buttons, and a label):
First things first, removing the items, to do that we'll enter our remove button:
private void button2_Click(object sender, EventArgs e)
{
listView1.Items.Remove(listView1.SelectedItems[0]);
label1.Text = updateCartTotal().ToString();
}
Now the second line is updating our labels total using the next function i'll post to addup all the total of column 2 in the listview:
private decimal updateCartTotal()
{
decimal runningTotal = 0;
foreach(ListViewItem l in listView1.Items)
{
runningTotal += Convert.ToDecimal(l.SubItems[1].Text);
}
return runningTotal;
}
You don't have to use decimal like I did, you can use float or int if you don't have decimals. So let's break it down. We use a for loop to total all the items in the column 2(SubItems[1].Text). Add that to a decimal we declared prior to the foreach loop to keep a total. If you want to do tax you can do something like:
return runningTotal * 1.15;
or whatever your tax rate is.
Long and short of it, using this function you can retotal your listview by just calling the function. You can change the labels text like I demo'd prior if that's what you're after.
None of the answers above, at least to me, show how to actually handle determining whether you have 1 item or multiple, and how to actually get the values out of your items in a generic way that doesn't depend on there actually only being one item, or multiple, so I'm throwing my hat in the ring.
This is quite easily and generically done by checking your count to see that you have at least one item, then doing a foreach loop on the .SelectedItems, casting each item as a DataRowView:
if (listView1.SelectedItems.Count > 0)
{
foreach (DataRowView drv in listView1.SelectedItems)
{
string firstColumn = drv.Row[0] != null ? drv.Row[0].ToString() : String.Empty;
string secondColumn = drv.Row[1] != null ? drv.Row[1].ToString() : String.Empty;
// ... do something with these values before they are replaced
// by the next run of the loop that will get the next row
}
}
This will work, whether you have 1 item or many. It's funny that MSDN says to use ListView.SelectedListViewItemCollection to capture listView1.SelectedItems and iterate through that, but I found that this gave an error in my WPF app: The type name 'SelectedListViewItemCollection' does not exist in type 'ListView'.
foreach (ListViewItem itemRow in taskShowListView.Items)
{
if (itemRow.Items[0].Checked == true)
{
int taskId = Convert.ToInt32(itemRow.SubItems[0].Text);
string taskDate = itemRow.SubItems[1].ToString();
string taskDescription = itemRow.SubItems[2].ToString();
}
}
If you want to select single listview item no mouse click over it try this.
private void timeTable_listView_MouseUp(object sender, MouseEventArgs e)
{
Point mousePos = timeTable_listView.PointToClient(Control.MousePosition);
ListViewHitTestInfo hitTest = timeTable_listView.HitTest(mousePos);
try
{
int columnIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);
edit_textBox.Text = timeTable_listView.SelectedItems[0].SubItems[columnIndex].Text;
}
catch(Exception)
{
}
}
This works for single as well as multi selection list:
foreach (ListViewItem item in listView1.SelectedItems)
{
int index = item.Index;
//index is now zero based index of selected item
}
On mouse click, I would do it like this:
public static string GetSelectedItem(ListView list)
{
foreach (ListViewItem item in list.Items)
{
if (item.Selected)
return item.Text;
}
return null;
}
Well, I need to check if there exists duplicate items inside listview on my app, but... I don't know how.
The way to detect this is by checking the field "Tag", if they are the same, then delete the item.
A good way to find duplicates is to use a temporary hashset. This gives you an O(n) O(n log n) algorithm (see Rick Sladkeys comments) to detect duplicates. Example:
var tags = new HashSet<string>();
var duplicates = new List<Item>();
foreach(Item item in listView.Items)
{
// HashSet.Add() returns false if it already contains the key.
if(!tags.Add(item.Tag)
duplicates.Add(item);
}
[Remove duplicates here]
Used nested for loops to go through and check each item against each other item.
//tag duplicates for removal
List<Item> toRemove = new List<Item>();
foreach(Item item1 in listView.Items)
{
foreach(Item item2 in listView.Items)
{
//compare the two items
if(item1.Tag == item2.Tag)
toRemove.Add(item2);
}
}
//remove duplicates
foreach(Item item in toRemove)
{
listView.Items.Remove(item);
}
You'll have to tweak the syntax for your code, but that's the basic idea behind it. Also, there are optimizations that could probably be made to it, but don't worry about those yet.
None of the above helped me, so I thought I'd post what I came up with in case someone else is having this issue.
myListView is a ListView, sorted alphabetically (so duplicates in this case are adjacent). You could sort it programatically beforehand if you wanted.
myListView.Sorting = SortOrder.Ascending;
Anyway this is fairly simplistic but I hope it helps someone!
for (int i = 0; i < myListView.Items.Count - 1; i++)
{
if (myListView.Items[i].Tag == myListVIew.Items[i + 1].Tag)
{
myListView.Items[i + 1].Remove();
}
}
If you have a lot of items then you can use a HashSet to keep the performance acceptable.
Loop over the items starting with the HashSet empty. For each item check if the tag is in the HashSet. If so this is a duplicate. If not add the tag to the HashSet.
This approach avoids an N^2 algorithm which is what you get with a nested loop. The HashSet makes the algorithm linear complexity providing the removal phase is carefully implemented. Of course this may not matter to you depending on how many items you have. If the list is small use nested loops and keep it simple.
If you are comparing duplicated Items based on specific columns you should simply use:
if(listview.Items.Find(SearchQuery).Count > 0)
{
//remove duplicates from list...
}
but you should name every item in the list when you fill up the listview..
for example if I want to search for duplicate items in column 1+2+5 I'd name the whole row like:
myItemName.Name = column1.Text + "_" + column2.Text + "_" + column5.Text;
and then perform the above "if statement"..
I would like to offer my solution using a Dictionary for future reference:
(you will edit for your own "Colums" (subitems), Simply read the code to understand.
I used the below to remove "Dups" in a listview on a button click, i am searching subitem you can edit code for your own use...
uses dictionary and a little easy "update" class i wrote.
private void removeDupBtn_Click(object sender, EventArgs e)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
int num = 0;
while (num <= listView1.Items.Count)
{
if (num == listView1.Items.Count)
{
break;
}
if (dict.ContainsKey(listView1.Items[num].SubItems[1].Text).Equals(false))
{
dict.Add(listView1.Items[num].SubItems[1].Text, ListView1.Items[num].SubItems[0].Text);
}
num++;
}
updateList(dict, listView1);
}
and using a little updateList() class...
private void updateList(Dictionary<string, string> dict, ListView list)
{
#region Sort
list.Items.Clear();
string[] arrays = dict.Keys.ToArray();
int num = 0;
while (num <= dict.Count)
{
if (num == dict.Count)
{
break;
}
ListViewItem lvi;
ListViewItem.ListViewSubItem lvsi;
lvi = new ListViewItem();
lvi.Text = dict[arrays[num]].ToString();
lvi.ImageIndex = 0;
lvi.Tag = dict[arrays[num]].ToString();
lvsi = new ListViewItem.ListViewSubItem();
lvsi.Text = arrays[num];
lvi.SubItems.Add(lvsi);
list.Items.Add(lvi);
list.EndUpdate();
num++;
}
#endregion
}
Good luck!
int J = 0;
In this simple code we will remove duplicates from a loop which will take the first item and compare it with the items bellow, so if it exists you can remove the above one or the second one
foreach (ListViewItem item1 in listView1.Items)
{
//J+1 to do not repeat the list from first and remove itself just take a look on next items
for (int i=J+1;i<listView1.Items.Count-1;i++)
{
//i compare two subitems that must be unique in my list
if (listView1.Items[J].SubItems[1].ToString() == listView1.Items[i].SubItems[1].ToString())
// listView1.Items.RemoveAt(i); // remove the second one
listView1.Items.RemoveAt(J); // remove the first one and keep the second
}
J++;
}
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