I am trying to get a list of all elements from ListBox if no or one of items is selected or list of selected items if more than 1 are selected. I have written such a code but it doesn't compile :
ListBox.ObjectCollection listBoXElemetsCollection;
//loading of all/selected XMLs to the XPathDocList
if (listBoxXmlFilesReference.SelectedIndices.Count < 2)
{
listBoXElemetsCollection = new ListBox.ObjectCollection(listBoxXmlFilesReference);
}
else
{
listBoXElemetsCollection = new ListBox.SelectedObjectCollection(listBoxXmlFilesReference);
}
So for this piece of code to work I would need to use something like ListBox.SelectedObjectCollection listBoxSelectedElementsCollection; which I do not want because I would like to use it in such an foreach:
foreach (string fileName in listBoXElemetsCollection)
{
//...
}
I'd simply this a bit and not mess with the ListBox ObjectCollections if you don't need to. Since you want to iterate items on your ListBox as strings, why not use a List and load the list how you show:
List<string> listItems;
if (listBoxXmlFilesReference.SelectedIndices.Count < 2) {
listItems = listBoxXmlFilesReference.Items.Cast<string>().ToList();
} else {
listItems = listBoxXmlFilesReference.SelectedItems.Cast<string>().ToList();
}
foreach (string filename in listItems) {
// ..
}
You need to convert SelectedObjectCollection to an array of object[].
ListBox.SelectedObjectCollection sel = new
ListBox.SelectedObjectCollection(listBoxXmlFilesReference);
ListBox.ObjectCollection col = new
ListBox.ObjectCollection(listBoxXmlFilesReference,
sel.OfType<object>().ToArray());
I can see what you're trying to do and it doesnt compile because the type ListBox.ObjectCollection is not the same as ListBox.SelectedObjectCollection - even though in your case they are lists that contain strings the classes themselves are different hence the compile error.
Assuming your items are strings in the listbox you could do:
var items = listBoXElemetsCollection.Items.OfType<string>();
if (listBoXElemetsCollection .SelectedIndices.Count >= 2)
items = listBoXElemetsCollection.SelectedItems.OfType<string>();
foreach(var item in items)
//do stuff
Related
My code correctly identifies listview rows based on a textbox search criteria. However when I try to remove the unwanted row(s) I get an error message:-
InvalidArgument=Value of '-1' is not valid for 'index'.
I would be very grateful if someone could help me resolve this issue.. Thanks in advance.
foreach (ListViewItem item in listView1.Items){
foreach (ListViewItem.ListViewSubItem subItem in item.SubItems){
if (subItem.Text.ToLower().StartsWith(textBox1.Text.ToLower())){
var index = item.Index;
int.TryParse(listView1.Items[index].SubItems[4].Text, out val);
store[pos] = val;
pos++;
count++;
}else{
listView1.Items[index].Remove();
}
}
}
The problem is that you do not calculate your index in clause 'else'
}else{
listView1.Items[index].Remove();
}
You can't remove items from a collection you are iterating through Foreach, c# will throw an error because the collection changed, use for instead, and do it from the end to beginning (so you won't jump items when removing)
Try this approach:
Comments are in the code. Feel free to ask if you need additional explanation.
solution w/ Linq
using System.Linq;
...
//cast ListViewItemCollection as List<ListViewItem> for easier manipulation
var items = listView1.Items.Cast<ListViewItem>();
//first, get all items that don't have text matching with textBox text
List<int> itemIndexes =
items
.Where(item => !item.Text.ToLower().StartsWith(textBox1.Text.ToLower()))
.Select(item => item.Index).ToList();
int val;
//now, with all those indexes do your stuff
itemIndexes.ForEach(index =>
{
int.TryParse(listView1.Items[index].SubItems[4].Text, out val);
store[pos] = val;
pos++;
count++;
});
//lastly, sort indexes descending (for example: 10, 5,4,1) and remove them from listview
itemIndexes
.OrderByDescending(i=>i)
.ToList()
.ForEach(index => listView1.Items.RemoveAt(index));
EDIT: chaged code that it removes items that don't start with text box' text (like OP wanted).
EDIT 2: since you don't want to use Linq, you can solve your problem using plain old lists and loops
Main thing is, as I said in a comment, not to remove items inside of foreach loop but after you found all items that need to be removed.
Code is tested and working (without 4 lines with missing variables store, val etc ...)
solution w/o Linq
//list to hold intem indexes
List<int> itemIndexes = new List<int>();
foreach (ListViewItem item in listView1.Items)
{
foreach (ListViewItem.ListViewSubItem subItem in item.SubItems)
{
var index = item.Index;
if (subItem.Text.ToLower().StartsWith(textBox1.Text.ToLower()))
{
//your code (which doesnt compile since you didn't paste whole code)
//to test this, I had to remove following 4 lines.
int.TryParse(listView1.Items[index].SubItems[4].Text, out val);
store[pos] = val;
pos++;
count++;
}
else
{
itemIndexes.Add(index);
}
}
}
//lastly, sort indexes descending (for example: 10, 5,4,1)
//because if you remove item 1, whole list will shorten and
//you'll get index out of bounds error (in last step when
//trying to remove item with 10 but last index is 7)...
itemIndexes.Reverse();
//... and remove them from listview
foreach (int index in itemIndexes)
{
listView1.Items.RemoveAt(index);
}
tested with sample data - code will remove items that don't start with a, like bbb and dd)
ListView listView1 = new ListView();
listView1.Items.Add("aaa");
listView1.Items.Add("bbb");
listView1.Items.Add("ax");
listView1.Items.Add("dd");
TextBox textBox1 = new TextBox();
textBox1.Text = "a";
I have typed numbers in a textbox and added them into a listBox. Now I need to order that listbox. This is my try:
int[] array = listBox1.Items.Cast<int>().ToArray<int>();
Array.Sort(array);
listBox1.Items.Clear();
foreach (int item in array)
{
listBox1.Items.Add(item);
}
It throws an 'System.InvalidCastException'. But I can't figure it out HOW to solve it.
You can use a lambda
var array = listBox1.Items.OfType<string>().Select(x => int.Parse(x))
.ToArray();
First, I want to say that it is not a good idea to store data inside a control. Always put your data inside types that can handle them like a List, Dictionary, etc. and then bind that to your listbox object. I guess you are working on windows forms. Then add a property to your form and put all your data in it.
something like this
public partial class Form1 : Form
{
List<string> _items = new List<string>(); // <-- Add this
public Form1()
{
InitializeComponent();
_items.Add("One"); // <-- Add these
_items.Add("Two");
_items.Add("Three");
listBox1.DataSource = _items;
}
public void add()
{
_items.Add("four");
_items.Sort();
}
}
This is as simple as
listBox1.Sorted = true;
UPDATE
var array = new object[listBox1.Items.Count];
listBox1.Items.CopyTo(array, 0);
listBox1.Items.Clear();
var sortedArray = array.Select(n => (object)Convert.ToInt32(n)).OrderBy(n => n).ToArray();
listBox1.Items.AddRange(sortedArray);
ListBox items can cast to string. So, You must cast it to string[], then convert to int[], then sort it and finally add sorted data to ListBox.
string[] strArray = listBox1.Items.Cast<string>().ToArray();
int[] intArray = strArray.Select(x => int.Parse(x)).ToArray();
Array.Sort(intArray);
listBox1.Items.Clear();
foreach (int item in intArray)
{
listBox1.Items.Add(item);
}
I hope this will be useful.
I am populating a listBox at runtime from a database as follows:
List<FILE_REPORT_TYPES> ReportTypes = GetReportTypesFromDatabase(ReportMappingIds)
BindingList<FILE_REPORT_TYPES> pbReportTypesBindingList = new BindingList<FILE_REPORT_TYPES>(ReportTypes);
listBoxReports.DataSource = ReportTypesBindingList;
listBoxReports.DisplayMember = "REPORT_DESCRIPTION";
listBoxReports.ValueMember = "REPORT_ID";
I then would like select multiple items on the listBox when running the windows form and retrieve each individual Value of my selections. If only one selection is made one could do the following:
listBoxReports.SelectedValue;
I would like to do the following:
var list = listBoxReports.SelectedValues;
However this is not allowed i.e. "SelectedValues" does not exist.
Some people are erroneously suggesting that in this particular case SelectedIndices may be used. It cannot be used, I am trying to retrieve the "VALUE". This cannot be done (in this particular case):
listBox.Items[i].Value;
I think the solution should be along the lines of:
foreach(var line in listBox.Items)
{
var res= ((SOME CASTING)line).Value;
}
To get the selected items you have 2 options
a.) ListBox.SelectedIndices which returns the indices of the selected items which you then need to use to look up in the Items property what the value is or
b.) ListBox.SelectedItems which returns you a collection with the selected items themselves (be aware that it is an objectlist so you need to transform the items into your appropriate datatype).
Edit: With the additional information the following is possible
List<FILE_REPORT_TYPES> mySelectedList = new List<FILE_REPORT_TYPES>();
foreach (Object selectedItem in ListBox.SelectedItems)
{
mySelectedList.Add( ((FILE_REPORT_TYPES)selectedItem) );
}
You can use ListBox.SelectedIndices or ListBox.SelectedItems.
If you want to get all selected-items, you can let the foreach cast:
foreach(FILE_REPORT_TYPES frt in listBox.SelectedItems)
{
// ...
}
or if you want to get the ReportID into a list with the help of LINQ:
List<decimal> reportIds = listBox.SelectedItems.Cast<FILE_REPORT_TYPES>()
.Select(frt => frt.REPORT_ID)
.ToList();
Alternative to the selected value you could do the following
listBoxReports.SelectedItems;
Answer (the casting is the trick):
List<decimal> reportIds = new List<decimal>();
foreach(var line in listBoxReports.SelectedItems)
{
reportIds.Add(((PB_FILE_REPORT_TYPES)line).REPORT_ID);
}
You may try like below
List<FILE_REPORT_TYPES> reportList = new List<FILE_REPORT_TYPES>();
foreach(var item in listBox.SelectedItems)
{
reportList.Add((FILE_REPORT_TYPES)item);
}
I am using a multi-selection ListPicker (the new one in the 7.1/Mango control toolkit from Nov '11).
My code is below - a "vanilla" use case for the ListPicker, except that I initialize the SelecetedItems dependency property with a new List so I can add things to it and properly initialize the selected state for the ListPicker. Although this issue repro's whether or not I do this...
The SummaryForSelectedItemsDelegate does get called when initializing the list (e.g. when I call contactPicker.SetValue(ListPicker.SelectedItemsProperty)), but NOT when I click the "done" button on the ListPicker (although my SelectionChanged event handler does get called).
Once I dismiss the ListPicker, I only get the string corresponding to the first selected item in the "summary" for the control (as opposed to the control calling my delegate and getting a comma-delimited list of selected items).
Is this a bug? Has anyone else run into this? Is there a workaround?
var contactPicker = new ListPicker()
{
MinWidth = minWidth,
ExpansionMode = ExpansionMode.FullScreenOnly,
SelectionMode = SelectionMode.Multiple,
SummaryForSelectedItemsDelegate = (list) => { return CreateCommaDelimitedList(list); },
IsTabStop = true
};
contactPicker.ItemsSource = listOfItems;
contactPicker.DisplayMemberPath = "Name";
contactPicker.SetValue(ListPicker.SelectedItemsProperty, new List<Item>());
// initialize the list picker selected values
foreach (var contactRef in listOfSelectedContacts)
contactPicker.SelectedItems.Add(contactRef);
contactPicker.SelectionChanged += new SelectionChangedEventHandler((o, ea) =>
{
// add all the newly added items
foreach (var added in ea.AddedItems)
{
Item addedItem = added as Item;
if (addedItem == null)
continue;
listOfSelectedContacts.Items.Add(addedItem);
}
// remove all the newly removed items
foreach (var removed in ea.RemovedItems)
{
Item removedItem = removed as Item;
if (removedItem == null)
continue;
listOfSelectedContacts.Items.Remove(removedItem);
}
});
I should have posted my my summary delegate... which is actually where my bug was :-(
Even though I was creating the SelectedItems as a List, and each of the elements in the IList passed in are typed "Item", the concrete type of the IList passed in is NOT List. Therefore the null check succeeds and the method returns null. And of course my breakpoint was right after that line so it looked like the method wasn't getting invoked. Duh.
private string CreateCommaDelimitedList(IList ilist)
{
IList<Item> list = ilist as IList<Item>;
if (list == null)
return null;
// build a comma-delimited list of names to display in a control
List<string> names = list.Select(it => it.Name).ToList();
StringBuilder sb = new StringBuilder();
bool comma = false;
foreach (var name in names)
{
if (comma)
sb.Append(", ");
else
comma = true;
sb.Append(name);
}
return sb.ToString();
}
Page 1: (sending listbox items into a list and saving the list as a session variable)
List<string> list = new List<string>();
foreach(ListItem item in ListBox1.Items)
{
list.Add(item.ToString());
}
Session["temp"] = list;
Page 2: (copying the session variable into a list and assigning the list to a listbox in this page)
List<string> list = new List<string>();
list = (List<string>)Session["JobRole"];
foreach (ListItem item in list)
{
ListBox2.Items.Add(item.ToString());
}
On doing so, this is the error i m getting : Cannot convert type 'string' to 'System.Web.UI.WebControls.ListItem'
can anyone pls help me with this ??
Thanks
Don't you mean
foreach (string item in list)
{
ListBox2.Items.Add(item);
}
... list is a list of strings after all.
That's because you have defined list as List. If you simply want to add the string value into the listbox you can do:
List<string> list = new List<string>();
list = (List<string>)Session["JobRole"];
foreach (string item in list)
{
ListBox2.Items.Add(item);
}
Also you should check that Session["JobRole"] is not null.