Search code examples
c#listweb-controls

Control is removed from old parent control but not if i use a List<Control>, why?


It's probably a very basic question about the behaviour of C# and WebControl. I got this working, but it would be nice if someone could clarify where the difference lays.

Before

I have a dictionary with a given key (Guid) and a Panel.

var tmpFormButtonPanel = new Panel();
 _formButtonPanelDict.TryGetValue(new Guid(_hiddenField.Value), out tmpFormButtonPanel);

This panel contains a WebControl. Now I'd like to assign this button to another panel.

if (tmpFormButtonPanel != null)
{
       var tmpControls = new List<Button>();
       foreach (Button tmpButton in tmpFormButtonPanel.Controls)
       {
            tmpControls.Add(tmpButton);
       }
       tmpControls.Reverse();
       foreach (var tmpButton in tmpControls)
       {
           tmpButton.AddCssClass("xy");
           _buttonPanel.Controls.Add(tmpButton);
       }
}

The moment I add the button to the _buttonPanel, it deletes the button out of tmpFormButtonPanel. From what I've heard or read, a WebControl can only be assigned to one panel. So this would explain why it doesn't work.

So I changed the code to this.

var tmpFormButtonList = new List<ButtonBaseUc>();
 if (!_formButtonDict.TryGetValue(new Guid(_hiddenField.Value), out tmpFormButtonList))
{
       tmpFormButtonList = new List<ButtonBaseUc>();
       _formButtonDict.Add(new Guid(_hiddenField.Value), tmpFormButtonList);
}
foreach (var tmpButton in tmpFormButtonPanel.Controls)
{
       if (tmpButton is ButtonBaseUc)
       {
            tmpFormButtonList.Add((ButtonBaseUc)tmpButton);
       }
}

The last part does the same thing, but on the tmpFormButtonList.

if (tmpFormButtonList!= null)
{
    var tmpControls = new List<Button>();
    foreach (Button tmpButton in tmpFormButtonList)
    {
         tmpControls.Add(tmpButton);
    }
    tmpControls.Reverse();
    foreach (var tmpButton in tmpControls)
    {
          tmpButton.AddCssClass("xy");
          _buttonPanel.Controls.Add(tmpButton);
     }
  }

This is working. But why? I am only assigning the button to another list before adding it to the new panel. The references are still the same. What am I missing?


Solution

  • A control can only belong to one parent control. Since you have assigned it to the Panel in the dictionary-value, it will be removed there if you move it to the _buttonPanel.

    This isn't documented but you can see it in the source:

    // ...
    if (control._parent != null) {
       control._parent.Controls.Remove(control);
    }
    

    You have fixed this by not using a Panel as "storage" but a List<ButtonBaseUc>. This list is not a control(so the control has no parent), hence it must not be removed if you assign it to another (parent-)control.