Home > Net >  Removing labels which name starts with a certain text
Removing labels which name starts with a certain text

Time:08-24

How can I remove all labels where Name starts with "ToClear"?

I tried this code, but it clears them in two clicks (if there are 26 labels it only removes 13 per click)

private void ClearLabel()
{
    foreach (var _object in this.Controls)
    {
        Console.WriteLine(((Label)_object).Name);
        if (_object is Label && ((Label)_object).Name.StartsWith("ToClear"))
        {
            this.Controls.Remove(this.Controls[((Label)_object).Name]);
        }
    }
}

CodePudding user response:

I wonder that it does not throw an exception. You are enumerating a collection and inside of this loop you are modifying the source. Instead you should collect the controls to remove and then remove them. Easy and readable with LINQ:

var lblRemove = this.Controls.OfType<Label>().Where(l => Name.StartsWith("ToClear")).ToList();
lblRemove.ForEach(this.Controls.Remove);

Note that it will not find nested controls(like your approach). Therefore you have to use a recursive loop, like this: https://stackoverflow.com/a/65855106/284240

CodePudding user response:

The problem was the loop was modifying the collection while still looping over it. That's a no-no. You can do this:

private void ClearLabel()
{
    SuspendLayout();
    var toRemove = Controls.Where(c => c is Label && c.Name.StartsWith("ToClear")).ToList();
    foreach(var control in toRemove)
    {
        Controls.Remove(control);
    }
    ResumeLayout();
}

CodePudding user response:

recurse. You can't remove while enumerating. Make a list first, then remove

NOTE: this works for the nested controls

private removeList = new Dictionary<Control, Label>();

private void EnumerateLabels(Control ctrl)
{
    foreach (var c in ctrl.Controls)
    {
        if (c is Label && c.Name.StartsWith("ToClear"))
            removeList.Add(ctrl, c);

        EnumerateLabels(c); // recurse children
                        
    }
}

usage

// assuming `this` is a form
EnumerateLabels(this);

foreach (var kvp in removeList)
    kvp.Key.Controls.Remove(kvp.Value);

Disclaimer - not tested

CodePudding user response:

You can do it via RemoveAll:

this.Controls.RemoveAll(c => (c is Label) && c.Name.StartsWith("ToClear"));

See more here: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.removeall?view=net-6.0

  • Related