-1

My problem is that when I compare two, absolutely the same tags, they turn out to be different instead.

The description of a code: I create 3 controls (button, label and a textbox) and assign the same tag (let's say, 0) to them all. When I press this newly created button, I want to delete all of the 3 controls with the same tag.

Code for adding the buttons (simplified):

int Count = 0; // This var changes, but for the example it is 0

Button newButton = new Button();
newButton.Tag = Count;
newButton.Click += new EventHandler(DeleteName);
Controls.Add(newButton);

Label newLabel = new Label();
newLabel.Tag = Count;
Controls.Add(newLabel);

And the same for a TextBox.

The coding behind deleting:

private void DeleteName(object sender, EventArgs e)
        {
            List<Control> toDelete = new List<Control>();

            Button btn = sender as Button;

            foreach (Control c in Controls) 
            {
                if (c.Tag == btn.Tag)
                toDelete.Add(c);
            }

            int tmp = toDelete.Count;

            for (int i = 0; i < tmp; i++)
            {
                Controls.Remove(toDelete[i]);
            }
        }

It used to work perfectly when I did the same logic before, but now it just deletes the button and no other control (the textbox and label stay untouched). When I replace "if (c.Tag == btn.Tag)" with, for example, "if (c is TextBox)", it adds all the TextBoxes to the list and deletes them, so I believe the problem is in this comparison of Tags.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
Ivan Mate
  • 3
  • 2
  • What changed between when "It used to work perfectly" and "now"? Did you put a bunch of controls inside another container control? If so, you need to query those separately. Have you verified that the other controls you expect to delete have the same tag as the button you're pressing to trigger this event? – Rufus L Apr 13 '18 at 23:40
  • It used to work perfectly before I accidentally deleted the whole method and had to re-write it completely. I didn't add the controls to any container. Yes, I have checked with a messagebox that all of those controls have a tag "0", exactly the same. – Ivan Mate Apr 13 '18 at 23:42
  • You said "The description of a code: I create 3 controls..." but you're not creating any controls. Are you adding them manually first? – wazz Apr 13 '18 at 23:44
  • I didn't include the code for adding the controls to the topic. I use the following logic: Count = 0; Button newButton = new Button(); newButton.Tag = Count; Controls.Add(newButton); Label newLabel = new Label(); newLabel.Tag = Count; Controls.Add(newLabel); And the same for a textbox – Ivan Mate Apr 13 '18 at 23:47
  • I'd edit your question to put your add code inside the question, rather than here in the comments. – Alan Apr 13 '18 at 23:51
  • 1
    I suggest you step through the code and see what values are set for `btn.Tag` and `c.Tag`. – John Wu Apr 13 '18 at 23:55
  • So, I've stepped through the code. On the corresponding buttons, c.Tag = 0 and btn.Tag = 0, but the "toDelete.Add(c);" part is never executed for whatever reason, I've completely lost my mind with this thing. – Ivan Mate Apr 14 '18 at 00:10
  • Maybe you need to add `.ToString()` on your `Tag`? The `==` operator is acting on an object (reference type) and you've assigned it a value type. See my answer below... – Rufus L Apr 14 '18 at 00:14

1 Answers1

0

The likely reason you're running into this is that Tag is an object, so the equality comparison will do a reference comparison, but you're setting it to a value type. And even if you were setting it to a reference type, the comparison would only return true if they were pointing to the exact same object.

One way to solve this would be to cast the Tag to the appropriate type, or, more commonly, use the ToString() method for comparison. We should also add null conditional operators in the check, in case a Tag is null, to avoid a NullReferenceException:

if (c.Tag?.ToString() == btn.Tag?.ToString())

Another thing you might consider doing is creating a separate method to delete all controls with a particular tag, and another one that recursively finds all controls with that tag. This will help out if you are in a situation where you have some controls with the "delete" tag that are children of a different container.

For example:

// Returns all controls under the parent with the specified tag
private List<Control> GetTaggedControls(string tag, Control parent)
{
    var taggedControls = new List<Control>();

    foreach (Control control in parent.Controls)
    {
        if (control.Tag?.ToString() == tag)
        {                
            taggedControls.Add(control);
        }

        // Recursively call this method in case this is a container
        taggedControls.AddRange(GetTaggedControls(tag, control));
    }

    return taggedControls;
}

// Deletes all controls with the specified tag
private void DeleteControlsWithTag(string tag)
{
    foreach (Control control in GetTaggedControls(tag, this))
    {
        Controls.Remove(control);
    }
}

For example, if you add the code below to a new WinForm project, it will create 10 labels with every other one containing a Tag with "deleteMe". It also creates a button that, when clicked, calls the DeleteControlsWithTag method above:

private void Form1_Load(object sender, EventArgs e)
{
    var padSpace = 5;
    var height = 15;

    // Add 10 labels, with a common tag on every other one
    for (int i = 0; i < 10; i++)
    {
        Controls.Add(new Label
        {
            Text = $"Label {i}",
            Top = padSpace * (i + 1) + height * i,
            Height = height,
            Visible = true,
            Tag = i % 2 == 0 ? "deleteMe" : "saveMe"
        });
    }

    // Add a button that will delete controls with deleteMe tag
    var btn = new Button
    {
        Text = "Delete Even Labels",
        Height = 20,
        Width = 150,
        Top = padSpace * 11 + height * 10,
        Visible = true
    };

    btn.Click += (o, ea) => { DeleteControlsWithTag("deleteMe"); };

    Controls.Add(btn);
}
Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • "if (control.Tag.ToString() == tag)" gives me a System.NullReferenceException. When I tried to comare "if (c.Tag.ToString() == btn.Tag.ToString()), I had the same exception. Maybe the problem hides somewhere here? Why could this be happening? – Ivan Mate Apr 14 '18 at 00:25
  • Oops, forgot to add the null conditional operator...updated now. It appears that some of your tags are null and we weren't checking that first. – Rufus L Apr 14 '18 at 00:28
  • That is a huuuge answer and I'm extremely thankful for what you have written down for me. I'm surprised I got such an informative answer in such a short time. In the end, merely changing my "if (c.Tag == btn.Tag)" into "if (c.Tag?.ToString() == btn.Tag?.ToString())" solved the problem and everything works like a charm. But I surely will try to understand all the other code you've suggested. Thank you very much! I promise that I will help newcomers, too. Once I begin to understand more, of course :) – Ivan Mate Apr 14 '18 at 00:35