What is the cleanest way to remove a control from a container?

I have a WinForms performance issue that may be related to what I dynamically add and then remove hundreds of controls.

EDIT {The application displays a timeline consisting of controls representing historical events. Controls are added, deleted, or moved depending on the transition time. Performance problems are associated not only with adding and removing controls (I can live with this), but even after I switch to time without any historical events (this means that the controls are not currently displayed). After jumping and getting time when there are no events on the chart, some actions in the graphical interface still take a lot of time, for example, opening a menu or opening dialog boxes. It is strange that other actions with a graphical interface, such as pressing buttons, do not stop. }

Despite the fact that the memory consumption is completely stable, can there be a problem with the release of resources?

To remove a control, I do two things:

  • Unregister callbacks from all events,
  • Challenge containerPanel.Controls.Remove(control).

Thank!

+3
source share
6 answers

You may have problems due to GC pressure, i.e. the garbage collector often works because many objects are created and then freed. when the GC is running, all threads stop on their tracks (almost), and the application looks like it is freezing

I don’t think that you are doing something wrong with the delete code, but maybe you can somehow cache the controls? can you tell us a little more about your script?

-edit -

, , , , , ( ), . wpf UI-, ui,

, , . , , , . , -- , )

+3

, . , , . " " , , .
, SuspendLayout ResumeLayout

SuspendLayout();
for(...)
    AddControl(...);
ResumeLayout();

SuspendLayout();
for(...)
    RemoveControl(...);
ResumeLayout();
+6

-, WinForms .

ControlCollection.Remove ArrayList.RemoveAt. , . , Array.Copy , ArrayList, .

, :

,

ArrayList l = new ArrayList();
foreach (Control c in Controls){
    if (ShouldKeepControl(c))
        l.Add(c);
    else
        UnhookEvents(c);
}
SuspendLayout();
Controls.Clear();
Controls.AddRange((Control[])l.ToArray(typeof(Control)));
ResumeLayout();

/* Example assumes your controls are in the best possible
   order for this technique. If they were mostly at the end
   with a few in the middle a modified version of this
   could still work. */
int i = Controls.Count - 1;
bool stillRemoving = true;
SuspendLayout();
while (stillRemoving && i >= 0){
    Control c = Controls[i];
    if (ShouldRemoveControl(c)){
        UnhookEvents(c);
        Controls.RemoveAt(i);
        i--;
    }else{
        stillRemoving = false;
    }
}
ResumeLayout();

, .

+2

WinForm, , . , .

, . , , , .

+1
source

Since it Controlimplements IDisposable, you should also remove the utility after removing it from your container.

containerPanel.Controls.Remove(control);
control.Dispose();
+1
source

Ok, that looks funny, but for me, the only solution that worked fine for me was

  For i = 0 To 3 ' just to repeat it !!
            For Each con In splitContainer.Panel2.Controls
                splitContainer.Panel2.Controls.Remove(con)
                con.Dispose()
                'con.Visible = False
            Next
        Next
  • using the suspendLayout () and resumeLayout () methods !!!
0
source

All Articles