Selecting multiple Listbox items through code - c#

Hi there I have searched for a while now and can't seem to find a solution to my problem, I have tried multiple methods to select multiple items in my listbox through code however none have worked, The best result I got was 1 selected item in my listbox.
Basically I want to select multiple items of the same value.
below is my code, sorry if I seem newbie but I am new to programming and still learning basic stuff.
foreach (string p in listBox1.Items)
{
if (p == searchstring)
{
index = listBox1.Items.IndexOf(p);
listBox1.SetSelected(index,true);
}
}
So as you can see I am trying to tell the program to loop through all the items in my listbox, and for every item that equals "searchstring" get the index and set it as selected.
However all this code does is select the first item in the list that equals "searchstring" makes it selected and stops, it doesn't iterate through all the "searchstring" items.

As suggested in the comment, you should set SelectionMode to either MulitSimple or MultiExpanded depending on your needs, but you also need to use for or while loop instead offoreach, because foreach loop doesn't allow the collection to be changed during iterations. Therefore, even setting this Property won't make your code run and you will get the exception. Try this:
for(int i = 0; i<listBox1.Items.Count;i++)
{
string p = listBox1.Items[i].ToString();
if (p == searchstring)
{
listBox1.SetSelected(i, true);
}
}
You can set SelectionMode either in the Properties window when using designer or in, for instance, constructor of your Form using this code:
listBox1.SelectionMode = System.Windows.Forms.SelectionMode.MultiSimple;

Related

foreach Certain item is in a ListBox - Winform, C#

I would like to know how I could find the amount of times a certain item appears in a listbox
foreach (string Item in listBox1.Items)
{
Console.WriteLine("1 Item");
}
Console.ReadLine();
Unfortunately, that cycles through the entire listBox. I only want a certain Item.
Assuming that listBox1.Items : List<string> or string[] ...
Option 1: listBox1.Items.Count(item => item == "YourCertainItem");
You could use Linq
Option 2: listBox1.Items.Where(item => item == "YourCertainItem").Count();
It would depend on the type of data you have bound to the ListBox and the types unique identifer (or the property you want to use for comparison).
For example, if you have bound a list of String to the Listbox, you could use
var result = listBox.Items.OfType<String>().Count(x=>x == valueToSearch);
Instead, if you have bound a Collection of Person Types to the ListBox, where Person.Id is the property you want to use for comparison, you could use
var result = listBox1.Items.OfType<Person>().Count(x=>x.Id == personToSearch.Id);
You need to begin by defining what would be the property you would compare the items in the ListBox by, after which you could use Linq as shown in the examples above.

Selecting Multiple ListBox items from GridView column

I have a databound Listbox with Multiselect enabled. On page load, I feed the information from a GridView column and select all the options that match, using this code:
string[] separators = { "<br />" };
String Departments = Session["ProjDept"].ToString();
string[] splitDepartments = Departments.Split(separators, StringSplitOptions.RemoveEmptyEntries);
foreach (var dept in splitDepartments)
{
listDepartment.SelectedIndex = listDepartment.Items.IndexOf(listDepartment.Items.FindByText(dept));
}
However, I am running into a strange issue: when there is only one department in the GridView column, the option in the listbox gets properly selected, but when there's multiple departments only the LAST department gets selected.
I've ran System.Diagnostics.Debug.Print(dept) within my foreach to ensure that all the values are getting passed and they all appear in the STDOUT, but the listbox still won't cooperate.
Any ideas as to how I can fix this -- or alternatively, what other code could I use to achieve the same results?
Thank you!
The SelectedIndex property only allows one value at a time, so you're resetting it with each iteration. That's why only the last one is being selected. You need to access the "Selected" property from the ListItem itself.
Without trying it myself, it should look something like:
foreach (var dept in splitDepartments)
{
int index = listDepartment.Items.IndexOf(listDepartment.Items.FindByText(dept));
listDepartment.Items[index].Selected = true;
}
As long as you do have SelectionMode="Multiple" - that code should work.

Multi value ListBox automatically selects undesired item

I have an object that has some attributes from the list selected - let's say a Promotion that can have 0 to X communication channels. To display/edit this information I am using a listbox with option SelectionMode==MultiExtended.
But in some cases it is behaving strangely
I have Promotion with 2 communication channels selected (first and last out of three channels),
I click on a second channel (that previously was the only unselected channel) and know it shows, that 1st and 2nd channels are selected (I placed a check at the beginning of the listbox SelectedIndexChanged event - and it shows that SelectedItems.Count==2, although I clicked on a single item not holding Ctrl or Shift keys) and in this case SelectedIndexChanged event is triggered twice in all other cases it is triggered just once
This happens only after the first time I open this dialogform, if I manually select 1st and 3rd item of Channels, and then click on the 2nd item - then it works properly
Screencast of a problem in action
http://screencast.com/t/lVs0e9oau
This is how I load list of all possible channels into listbox
foreach (var ct in Promotion_operations.Configuration.PromoCommunicationTypes)
{
KeyValuePair<string, PromotionCommunicationType> nct =
new KeyValuePair<string, PromotionCommunicationType>(ct.Name, ct);
communications.Add(nct);
}
PromotionCommunicationList.DataSource = communications; //Promotion_operations.Configuration.PromoCommunicationTypes;
PromotionCommunicationList.DisplayMember = "Key";
PromotionCommunicationList.ValueMember = "Value";
This is how I load selecteditems based on Promotion's data
private void LoadSelectedCommunicationsList(ListBox lstbox, List<PromotionCommunication> communications)
{
lstbox.SelectedItems.Clear();
foreach (var ct in communications)
{
for (int j = 0; j < lstbox.Items.Count; j++)
{
if (ct.CommunicationType.Id == ((KeyValuePair<string, PromotionCommunicationType>)lstbox.Items[j]).Value.Id)
{
lstbox.SelectedItems.Add(lstbox.Items[j]);
}
}
}
}
What could be the cause of this behaviour?
that clicking on one previously unselected list selects both - newly selected item and first item of the list?
Your PromotionCommunicationList and HistoryCommunicationList are sharing the same reference to your list of objects as DataSource. That said, they have the same BindingContext and share the same CurrencyManager. CurrencyManager is remembering selected items of your ListBox control and that's where your conflict is created because he's saving selected items of both of your ListBoxes. You already found the solution for your problem because new CurrencyManager is created when you set "different" list (the copy of your original one) as DataSource. Another possible solution would be the creation of new BindingContext for one of your ListBox controls.
You can try this out:
PromotionCommunicationList.DataSource = communications;
(..)
HistoryCommunicationList.BindingContext = new BindingContext(); // Add this
HistoryCommunicationList.DataSource = communications;
It should solve your problem. For more information about BindingContext check this link on MSDN.
I found the cause of the problem, though I don't really understand why it caused such a behaviour (if someone will answer that question, I will accept it as an answer to this question)
I had 2 listbox-es in my form and both of them where using the same collection as a Datasource, BUT!!! SelectedItems was selected using code (acctually it seems that in winforms it is not possible to databind listbox's selecteditems)
INITIALLY My code was:
PromotionCommunicationList.DataSource = communications;
(..)
HistoryCommunicationList.DataSource = communications;
Corrected version is:
PromotionCommunicationList.DataSource = communications.ToList();
(..)
HistoryCommunicationList.DataSource = communications.ToList();
I know that ToList() makes a copy, but I don't understand what's wrong with having the same collection as DataSource for list items of 2 listbox-es? Why does this have an impact on SelectedItems collection?

How to check if an item exists in more than one listbox? ASP.NET/C#

I have three sets of listboxes, I move items from lb1 to lb2, from lb3 to lb4 and from lb5 to lb6. The listboxes on the left contains the same items and I don't want the user to be able to submit the page if one or more items from the left listboxes is added to more than one listbox to the right. For example, item A in lb1, lb3 and lb5 can only be saved in either lb2, lb4 or lb6, not in two or three of them.
I want to perform this check before submitting the page (and later on I will add validation with javascript) and I wonder what is the most efficient way to do this.
Add all items to a list and check if there are any duplicates?
Thanks in advance.
Edit:
something like this:
List<string> groupList = new List<string>();
foreach (ListItem item in lbFullAccess.Items)
{
groupList.Add(item.Value.ToString());
}
foreach (ListItem item in lbContributor.Items)
{
groupList.Add(item.Value.ToString());
}
foreach (ListItem item in lblReadOnly.Items)
{
groupList.Add(item.Value.ToString());
}
Well, there's a hundred different ways you could do it. Absolutely nothing wrong with your suggestion of iteration.
You could have a little fun with LINQ:
public bool AreAllValuesUnique()
{
// Build up a linq expression of all of the ListItems
// by concatenating each sequence
var allItems = lbFullAccess.Items.Cast<ListItem>()
.Concat(lbContributor.Items.Cast<ListItem>())
.Concat(lbReadOnly.Items.Cast<ListItem>());
// Group the previous linq expression by value (so they will be in groups of "A", "B", etc)
var groupedByValue = allItems.GroupBy(i => i.Value);
// Finally, return that all groups must have a count of only one element
// So each value can only appear once
return groupedByValue.All(g => g.Count() == 1);
}
Not really sure about the performance of calling Cast (converting each element of the ListItemCollection to a ListItem, resulting in an IEnumerable) on each collection, but it is probably negligible.

Adding an item to a bound WPF ListBox

Ok, this has been a head scratcher for me. I have a ListBox I am binding to a linq query like so:
private IQueryable<Feed> _feeds;
public IQueryable<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = feedsQuery;
}
return _feeds;
}
}
public Options()
{
InitializeComponent();
this.DataContext = Feeds;
}
(For the record I've also tried List, instead of IQueryable)
Everything shows up great and I have a databound form that allows you to edit a record and all of those changes work just fine, the modified data shows up in the list.
The problem comes with I add an item. Nothing shows up in the list. The data goes into the database fine, but the only way to see the data is closing and restarting my app. I'm using the code below as an example:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
_db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
(with or without the _db.Refresh nothing happens)
What's going on?
You are doing everything right, you jus need to use ObservableCollection. This will notify the ListBox about any changes in the list and refresh it automatically.
From MSDN
In many cases the data that you work
with is a collection of objects. For
example, a common scenario in data
binding is to use an ItemsControl
such as a ListBox, ListView, or
TreeView to display a collection of
records.
P.S. you don't need a db refresh
Unless notified otherwise, the ListBox only iterates once over its ItemsSource. Your query is only being run once.
The query object doesn't know when the database changes (and Refresh doesn't help; see below)--it's up to you to know (or anticipate) that and to rerun relevant queries at the appropriate times.
Stan R mentions ObservableCollection. That's fine, but simply storing the result of your query in an ObservableCollection won't solve the problem unless you do some work to update the collection yourself when the database changes. This means rerunning the query and manually adding new items and removing deleted items from the collection. (You could alternatively just rerun the query and set the entire result back in to the ListBox, but that means a whole new set of items will be created--not very performant, and maybe not what you want for other reasons.)
As an aside, your call to DataContext.Refresh is probably not doing what you think it is. From the docs:
This method is useful after an optimistic concurrency error to bring items into a state for another attempt. It updates the state of the primitive fields and properties on the objects.
Okay. I'm not positive this is 100% the correct way to use the ObservableCollection, but this seems to work:
private ObservableCollection<Feed> _feeds;
public ObservableCollection<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = new ObservableCollection<Feed>();
foreach (var item in feedsQuery)
{
_feeds.Add(item);
}
}
return _feeds;
}
}
And add my item:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
// manually update the list
Feeds.Add(feed);
It took me a little while to figure out I had to update the list manually (thanks Ben), but it all seems to work. Sorting would be nice, but I'll worry about that another time.

Categories

Resources