Remove items from ListBox when DataSource is set - c#

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);

Related

Autocomplete for DatagridView ComboBox

I have a data grid view which is used to bind values.
I have a ComboBox inside this DatagridView; I want to implement an auto complete property in this ComboBox. It should not only search for the first letter but the whole item...
This can be done by
Grabbing the ComboBox
Manipulating its Items
Let's assume you have only one ComboBoxColumn; then you can grab an instance of the current one like this:
ComboBox editCombo = null; // class level variable
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
editCombo = e.Control as ComboBox;
if (editCombo != null)
{
// here we can set its style..
editCombo.DropDownStyle = ComboBoxStyle.DropDown;
editCombo.AutoCompleteMode = AutoCompleteMode.Suggest;
// sigh..:
editCombo.TextChanged -= editCombo_TextChanged;
editCombo.TextChanged += editCombo_TextChanged;
}
}
Let's assume you have the valid list of values in a List<string>
List<string>() allChoices = new List<string>();
Then we can adapt the Items to be shown in the TextChanged event:
void editCombo_TextChanged(object sender, EventArgs e)
{
List<String> items = allChoices.Select(x=>x)
.Where(x=>x.Contains(editCombo.Text)).ToList();
if (items.Count > 0)
{
editCombo.Items.Clear();
editCombo.Items.AddRange(items.ToArray());
}
editCombo.Select(editCombo.Text.Length, 0); //clear the selection
}
Note that this x=>x.Contains(editCombo.Text) searches for items that contain the full text entered. I hope that is what you mean; searching for items that are identical to the entered text makes no sense, as then you do not need to AutoComplete them anyway..

Add selected item from a bound listbox to a unbound listbox

i want to add selected item from a data bounded listbox (listbox1) to another listbox (listbox2)
Here is the code on a click event of a button.
private void btnrgt_Click(object sender, EventArgs e)
{
string x = listBox1.SelectedItem.ToString();
listBox2.Items.Add(x.ToString());
txttestno.Text = listBox2.Items.Count.ToString();
}
When i run this code System.data.datarowview get displayed in the listbox2.
Kindly help.
thank you in advance.
When you bind a ListBox datasource to a DataTable every item inside the ListBox is a DataRowView, not a simple string. In the ListBox you see a string displayed because you set the DisplayMember property of the ListBox with the name of a column in that DataRowView.
So, taking the current SelectedItem doesn't return a string but a DataRowView and calling ToString() for a DataRowView returns the full qualified name of the class (System.Data.DataRowView).
You need something like this
private void btnrgt_Click(object sender, EventArgs e)
{
DataRowView x = listBox1.SelectedItem as DataRowView;
if ( x != null)
{
listBox2.Items.Add(x["NameOfTheColumnDisplayed"].ToString());
txttestno.Text = listBox2.Items.Count.ToString();
}
}
EDIT
It is not clear what is the source of the error stated in your comment below, however you could try to avoid adding an item from the first listbox to the second one if that item exists in the second listbox with code like this
private void btnrgt_Click(object sender, EventArgs e)
{
DataRowView x = listBox1.SelectedItem as DataRowView;
if ( x != null)
{
string source = x"NameOfTheColumnDisplayed".ToString();
if(!listbox2.Items.Cast<string>().Any(x => x == source))
{
listbox2.Items.Add(source);
txttestno.Text = listBox2.Items.Count.ToString();
}
}
}
This solutions works if your second listbox is really populated adding simple strings to its Items collection.
On click button use below code.
protected void btnGo_Click(object sender,EventArgs e) {
string x = ListBox1.SelectedItem.Text;
ListBox2.Items.Add(x);
}

Need my listbox to update from a list

I have my listbox1 set to use a datasource of a list called "serverList". When I run
public void button2_Click(object sender, EventArgs e)
{
if (folderPath != "\\realmlist.wtf" && folderPath != "none")
{
serverList.Add(newServer);
listBox1.DataSource = serverList;
File.WriteAllText(folderPath, "Set realmlist " + newServer);
}
}
the first string enters and shows up in the listbox just fine but when I try to add another string to the list it wont show up in the listbox but is actually within the list. What can I do to accomplish this?
if winform app
BindingSource source=new BindingSource();
source.DataSource=serverList;
listBox1.DataSource = source;
if not you have to use listBox1.DataBind()
After assigning DataSource, you should bind the data i.e. listBox1.DataBind()

Select index from listview

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.

How to remove all ListBox items?

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;

Categories