dynamically delete controls from table - c#

Am trying to delete textboxes and labels while their names which have equal value from the selected items from the listbox. If i run this code only the first if statement is executed and removing only the label controls inside the table.
I must also mention that controls of the table are dynamically created.
private void pictureBox2_Click(object sender, EventArgs e)
{
for (int i = 0; i < listBox2.SelectedItems.Count; i++)
{
foreach (Control t in table2.Controls)
{
if (t is Label && t.Text==listBox2.SelectedItem.ToString())
{
table2.Controls.Remove(t);
continue;
}
if (t is TextBox && t.Name.Contains(listBox2.SelectedItem.ToString()))
{
table2.Controls.Remove(t); continue;
}
}
listBox2.Items.Remove(listBox2.SelectedItems[i]); i--;
}
}
This is how controls are created indide the table.
private void pictureBox1_Click(object sender, EventArgs e)
{
listBox2.Items.Clear();
this.table2.Controls.Clear();
foreach (var item in listBox1.SelectedItems)
{
table2.Controls.Add(new Label() { Name = item.ToString(), Text = item.ToString(), AutoSize = true });
table2.Controls.Add(new TextBox() { Name = item.ToString(), AutoSize = true });
}
}
}

When you remove an item from a collection (suppose the item at position 0), the item at the next position (postion 1) shifts in position zero. But your for loop execute the next iteration and your indexer becomes 1 and so it terminate the loop.
The first approach to avoid this is to loop in reverse order, from the end of the collection toward the begin of it
But you could also simplify a lot your code with
private void pictureBox2_Click(object sender, EventArgs e)
{
for (int i = listBox2.SelectedItems.Count - 1 ; i >= 0 ; i--)
{
// This is our search term...
string curItem = listBox2.SelectedItems[i].ToString();
// Get only the controls of type Label with Text property equal to the current item
var labels = table2.Controls
.OfType<Label>()
.Where (c => c.Text == curItem)
.ToList();
if(labels != null)
{
for(int x = labels.Count()-1; x >= 0; x--)
table2.Remove(labels[x]);
}
// Get only the controls of type TextBox with Name property containing the current item
var boxes = table2.Controls
.OfType<TextBox>()
.Where (c => c.Name.Contains(curItem)
.ToList();
if(boxes != null)
{
for(int x = boxes.Count()-1; x >= 0; x--)
table2.Remove(boxes[x]);
}
listBox2.Items.Remove(curItem);
}
}

Why are you decrementing your iterator at the end of your for loop? It looks like you're stuck in the loop, buddy.

Related

C# Check if items in checklistbox are un-checked?

I'm trying to list all items in a directory which has been successful. I need to check if the item's status is "Unchecked", and if it is to give me the name of it in a variable.
TL;DR: If item is unchecked, write item in variable.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (checkedListBox1.GetItemChecked(e.Index) == true)
{
if (checkedListBox1.CheckedItems.Count != 0)
{
// If so, loop through all checked items and print results.
string s = "";
for (int x = 0; x < checkedListBox1.CheckedItems.Count; x++)
{
if (checkedListBox1.CheckedItems[x] == 0)
{
s = checkedListBox1.CheckedItems[x].ToString();
}
}
MessageBox.Show(s);
}
}
}
This is my current code.
To get a list of all unchecked items:
private void button1_Click_1(object sender, EventArgs e)
{
List<String> items = new List<String>();
for (int i=0; i<checkedListBox1.Items.Count; i++)
{
if (!checkedListBox1.GetItemChecked(i))
{
items.Add(checkedListBox1.Items[i].ToString());
}
}
// ... do something with "items" ...
foreach(String item in items)
{
Console.WriteLine(item);
}
}

ListView.FindItemWithText inside WHILE loop fails after first ListView line

I want change the content of 2nd column of each line of ListView with diferents data according with is found via FindItemWith.
My trouble is that from of 2nd line is be overriding the previous columns, for example when i want change the content searching a text that stays on first line works fine, see:
Already when i want change the content searching a text that stays on second line this happens:
This is the code:
public void fillData(string search, string data, ListView haystack)
{
if (haystack.Items.Count > 0)
{
int idx = 0;
ListViewItem found;
while (idx < haystack.Items.Count)
{
found = haystack.FindItemWithText(search, true, idx);
if (found != null)
{
haystack.Items[idx].SubItems[1].Text = data.ToString();
}
idx++;
}
}
}
private void button3_Click(object sender, EventArgs e)
{
int i = 0;
while (i < 3)
{
ListViewItem item = new ListViewItem();
item.Text = i.ToString();
item.SubItems.Add("192.168.0." + i.ToString());
listView1.Items.Add(item);
i++;
}
}
private void button1_Click(object sender, EventArgs e)
{
fillData("192.168.0.0", "AAA", listView1);
}
private void button2_Click(object sender, EventArgs e)
{
fillData("192.168.0.1", "BBB", listView1);
}
This is because the overload function you used for FindItemWithText, keeps searching all the items from the index you passed in.
When the loop has idx = 0 then FindItemWithText will try to search all three items 0,1,2.
When the loop has idx = 1 then FindItemWithText will try to search two items 1,2.
When the loop has idx = 2 then FindItemWithText will try to search only one item 2.
So now in the first case, As you are searching for first item, your loop found it only once. But where as in second case you are searching for second item, it was found twice both (idx = 0 ---- 0,1,2) and (idx = 1 ---- 1,2) iterations. So you are updating two values both for idx=0 and idx = 1.
Here is the documentation link
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.listview.finditemwithtext?view=netframework-4.7.2#System_Windows_Forms_ListView_FindItemWithText_System_String_System_Boolean_System_Int32_
Any how FindItemWithText returns the System.Windows.Forms.ListViewItem. Just search once from zero. Use that item to update.

Cannot retrieve total indexof listview

I have a ListView control that I'm filtering results from with a TextBox. The code works for highlighting the backcolors of the matching results, but I want to get the total found results/highlighted objects as an int. The int that is populating now is incorrect and not in line with the found/highlighted results.
How can I get the total number of found/highlighted results?
private void textBox1_TextChanged(object sender, EventArgs e)
{
foreach (ListViewItem lvi in this.browserlistview.Items)
{
if (textBox1.TextLength > 0)
{
if (lvi.Text.IndexOf(textBox1.Text, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
Color b = Color.Cyan;
lvi.BackColor = b;
foundobjlbl.Text = "Objects found: " + lvi.Text.IndexOf(textBox1.Text, StringComparison.InvariantCultureIgnoreCase).ToString();
//this is turning up incorrect integers
}
else
{
Color w = Color.White;
lvi.BackColor = w;
}
}
else if (textBox1.TextLength == 0)
{
Color w = Color.White;
lvi.BackColor = w;
foundobjlbl.Text = "Objects found : 0";
}
}
}
Does anyone see where I'm going wrong?
You're setting your count to the index of the text you're looking for in a specific item. So you're setting it once for each item you've found, so what you'll get is the index of your search term in the last item found.
What you want is to track the count of found items and set it once the search is finished, so something like this (I've left out most of the other implementation details):
var foundCount = 0;
foreach (var item in items)
{
if (IsMatch(item))
{
// set colour
foundCount++;
}
else
{
// set white
}
}
foundobjlbl.Text = $"Objects found {foundCount}";

How to count duplicates from ListBox and show the number of duplicated items beside it?

So I have a button, where if you click it, it adds "Candy" to a listbox, how do I make it so, if another item with the same name is being added, instead of adding it in a new line, update the first line to show x2, 3, 4, etc. Is that possible or would I have to make another Listbox and match the index? I've tried the following with another listbox and an int variable.
private void btnCandy_Click(object sender, EventArgs e)
{
lstProducts.Items.Add("Candy");
foreach (var item in lstProducts.Items)
{
if (item.ToString() == "Candy")
{
++Productcount;
lstQuantity.Items.Add(Productcount);
if (Productcount > 1)
{
lstQuantity.Items.Insert(lstProducts.Items.IndexOf("Candy"), Productcount);
}
}
}
}
using System.Text.RegularExpressions;
Use:
private void btnCandy_Click(object sender, EventArgs e)
{
string query = "Candy";
bool isExist = false;
for (int i = 0; i < lstProducts.Items.Count; i++)
{
var s = lstProducts.Items[i].ToString();
if (s.StartsWith(query))
{
if (s == query)
{
lstProducts.Items[i] = query + "x2";
isExist = true;
break;
}
else
{
// Escape your plain text before use with regex
var pattern = Regex.Escape(query);
// Check if s has this formnat: queryx2, queryx3, queryx4, ...
Match m = Regex.Match(s, "^" + pattern + #"x(\d+)$");
if (m.Success)
{
lstProducts.Items[i] = query + "x" + (Int32.Parse(m.Groups[1].Value) + 1);
isExist = true;
break;
}
}
}
}
if (!isExist) lstProducts.Items.Add(query);
}
Note:
\d mean any digit (0 - 9)
I'd try to iterate through listbox items and if I find "Candy" then take that index and update title.
private void btnCandy_Click(object sender, EventArgs e)
{
bool found = false;
foreach (var item in lstProducts.Items)
{
if (item.ToString().StartsWith("Candy"))
{
// update item title
found = true;
break; // no need to continue
}
}
if(!found)
{
lstProducts.Items.Add("Candy");
}
}
this way you are not going to add duplicates
Here is some pseudo-code to help you. Add this to your button click event:
int i = 0;
foreach (string item in listbox1.Items)
{
If (item == textbox1.text) //textbox1.text contains the string such as 'candy'
{
i++;
listbox1.Items.Remove(item);
listbox1.Items.Add(textbox1.text + " " + i.ToString());
}
}
You may have to reset the counter as needed.

Count the number of controls - C# with the certain names?

C# - 2.0
I am trying to figure out on how to do a loop on a list of controls with certain names: "txtTesting[i]"
txtTesting1
txtTesting2
txtTesting3 ...
txtTesting13
With the code I have a total of 13. But this can change as time goes by. So I am looking to get the data from the textboxes that have data in them. I just can not seem to figure out a way to do a count of the controls. I have tried this...
for (int i = 1; i < 13; i++)
{
if (txtTesting[i].text != "")
{
//
}
}
I am also getting this error...
Error 51 The name 'txtTesting' does not exist in the current context
Unless I am missing something here.
System.Web.UI.WebControls.TextBox
Assuming this is a System.Windows.Forms application, you should be able to go through all your controls on the form and then select the ones that are TextBox as follows:
foreach (System.Windows.Forms.Control control in this.Controls)
{
if (control is System.Windows.Forms.TextBox)
{
if (((System.Windows.Forms.TextBox)control).Text != "")
{
// Do something
}
}
}
For an asp.net application this would be very similar:
foreach (System.Web.UI.Control control in this.Controls)
{
if (control is System.Web.UI.WebControls.TextBox)
{
if ((System.Web.UI.WebControls.TextBox)control).Text != "")
{
// Do something
}
}
}
txtTesting looks like an array. does it have a Length property?
for (int i = 1; i < txtTesting.Length; i++)
if it's a type List<T> than maybe it has a Count property
for (int i = 1; i < txtTesting.Count; i++)
If you don't already have an array, you can initialize one in your presumed Form's constructor
List<WhateverTypeTxtTestingIs> txtTesting = new List<WhateverTypeTxtTestingIs>();
txtTesting.Add(txtTesting1);
txtTesting.Add(txtTesting2);
...
The most efficient way would be to add the controls to an array and loop over that, but you could also loop through the controls and inspect the control's Name:
foreach(Control c in this.Controls) // <-- "this" may not be appropriate - you just need to reference the containing control
{
if(c.Name.StartsWith("txtTesting")
{
///
}
}
In your constructor, after the call to InitializeComponent, stuff the text boxes in a collection.
// class-scoped variable
private List<Textbox> _boxen = new List<TextBox>();
public MyFormDerp()
{
InitializeComponent();
_boxen.Add(txtTesting1);
// etc
_boxen.Add(txtTesting13);
}
and, later on...
foreach(TextBox box in _boxen)
if (box.text != "")
{
//
}
Also, your design should make you itch.
You can use a foreach over your array:
foreach (TextBox txt in txtTesting)
{
if (txt.text != "")
{
//
}
}
Or, the array has a length property that you can use.
for (int i = 1; i < txtTesting.length; i++)
{
if (txtTesting[i].text != "")
{
//
}
}
If you don't have an array of controls, you may want to look at this answer to loop through all the controls on your form. Except the generic Dictionary isn't in C# 2, so it will look more like this:
private void button1_Click(object sender, EventArgs e)
{
ArrayList txtTesting = ArrayList();
LoopControls(controls, this.Controls);
foreach (TextBox txt in txtTesting)
{
if (txt.text != "")
{
//
}
}
}
private void LoopControls(ArrayList list, Control.ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is TextBox && control.Name.StartsWith("txtTesting"))
list.Add(control);
if (control.Controls.Count > 0)
LoopControls(list, control.Controls);
}
}

Categories