Question

I ai une commande d'utilisateur qui contient un TableLayoutPanel deux colonnes et accepte les commandes pour ajouter dynamiquement des lignes à afficher les détails d'un élément sélectionné dans une commande séparée. Ainsi, l'utilisateur sélectionne une ligne dans l'autre commande (un DataGridView), et dans le gestionnaire d'événements SelectedItemChanged pour le DataGridView effacer le contrôle des détails et régénérer toutes les lignes pour le nouvel élément sélectionné (ce qui peut avoir un détail tout à fait différent affichage de l'élément précédemment sélectionné). Cela fonctionne très bien pendant un certain temps. Mais si je continue à passer d'un élément sélectionné à l'autre pour un temps assez long, les rafraîchissements deviennent très lentes (3-5 secondes chacun). Cela fait sonner comme je ne suis pas disposer tout correctement, mais je ne peux pas comprendre ce que je suis absent. Voici mon code pour effacer le TableLayoutPanel:

private readonly List<Control> controls;

public void Clear()
{
    detailTable.Visible = false;
    detailTable.SuspendLayout();
    SuspendLayout();
    detailTable.RowStyles.Clear();
    detailTable.Controls.Clear();
    DisposeAndClearControls();
    detailTable.RowCount = 0;
    detailTable.ColumnCount = 2;
}

private void DisposeAndClearControls()
{
    foreach (Control control in controls)
    {
        control.Dispose();
    }
    controls.Clear();
}

Et une fois que je fini de charger toutes les commandes que je veux dans la TableLayoutPanel pour l'affichage suivant détail voici ce que j'appelle:

public void Render()
{
    detailTable.ResumeLayout(false);
    detailTable.PerformLayout();
    ResumeLayout(false);
    detailTable.Visible = true;
}

Je n'utilise quoi que ce soit, mais les étiquettes (et une zone de texte très rarement) à l'intérieur du TableLayoutPanel, et j'ajouter les étiquettes et zones de texte à la liste des contrôles (référencés dans DisposeAndClearControls ()) quand je les crée. J'ai essayé juste itérer sur detailTable.Controls et les disposer de cette façon, mais il semblait manquer la moitié des contrôles (déterminés en marchant à travers elle dans le débogueur). De cette façon, je sais que je les ai tous.

Je serais intéressé par des suggestions pour améliorer les performances de dessin, mais surtout ce qui est à l'origine de la dégradation sur plusieurs sélections.

Était-ce utile?

La solution 3

J'ai changé la forme contenant juste construire une nouvelle version de mon contrôle utilisateur à chaque changement de sélection. Il dispose de l'ancien et construit un nouveau. Cela semble effectuer très bien. Je l'avais d'abord allé à la réutilisation juste une pour des raisons de performances de toute façon. Il est clair que cela n'améliore pas les performances. Et les performances ne sont pas un problème si je dispose l'ancien et créer un nouveau.

Malheureux que les fuites TableLayoutPanel comme ça, bien.

Autres conseils

Il suffit d'utiliser un contrôle personnalisé qui hérite de TableLayoutPanel et définir la propriété sur DoubleBuffered vrai, fonctionne très bien ... surtout quand vous ajoutez dynamiquement ou supprimer des lignes.

public CustomLayout()
{
   this.DoubleBuffered = true;
   InitializeComponent();
}

J'ai eu un problème similaire avec TableLayout. Si je TableLayout.Controls.Clear () méthode , contrôles enfants ne se est disposé mais quand je simplement laissé tomber le TableLayout sans l'effacer, la fuite a cessé. En rétrospective, il est drôle je la méthode Clear empêcher une sorte de fuite.

Apparemment, méthode Clear ne pas disposer explicitement des contrôles (ce qui est logique, parce que le fait que vous les avez retirés de la TableLayout ne signifie pas que vous avez terminé avec eux) et en supprimant les contrôles enfants du TableLayout empêche la routine de nettoyage de disposer des enfants lorsque le LayoutTable lui-même se disposé (il ne sait tout simplement pas les plus).

Ma recommandation: Supprimer le detailTable.Controls.Clear (); ligne, retirez le detailTable lui-même de contrôles du parent collection et d'en disposer, puis créer une nouvelle marque TableLayout pour le prochain tour. perdre également la méthode DisposeAndClearControls entièrement puisque vous aurez pas besoin. Dans mon expérience, il a travaillé bien.

De cette façon, vous ne serez pas avoir à recycler plus votre contrôle utilisateur en entier mais seulement la TableLayout à l'intérieur.

Je fait face au même problème et a trouvé un bon moyen sans changer trop:

dans VB.net

Dim tp As Type = tlpMyPanel.GetType().BaseType
Dim pi As Reflection.PropertyInfo = _
    tp.GetProperty("DoubleBuffered", _ 
    Reflection.BindingFlags.Instance _
    Or Reflection.BindingFlags.NonPublic)
pi.SetValue(tlpMyPanel, True, Nothing)

ou en C #:

Type tp = tlpMyPanel.GetType().BaseType;
System.Reflection.PropertyInfo pi = 
    tp.GetProperty("DoubleBuffered",
    System.Reflection.BindingFlags.Instance 
    | System.Reflection.BindingFlags.NonPublic);
pi.SetValue(tlpMyPanel, true, null);

Malheureusement, le seul conseil que je peux offrir est de prendre soin du placement de vos commandes vous-même. Dans mon expérience, la TableLayoutPanel .NET, tout en étant très utile, fuit quelque chose et devient lente unusably comme il grandit (et il ne prend pas un nombre excessif de cellules pour arriver à ce point, que ce soit). Ce comportement peut être vu dans le concepteur ainsi.

TableLayoutPanel.Controls.Clear () fonctionne très bien pour moi, peut-être son parce que je l'effacer d'un onglet différent de celui affiché dans son.

List<Control> controls = new List<Control>();
foreach (Control control in tableLayoutPanelEnderecoDetalhes.Controls)
{
    controls.Add(control);
}

foreach (Control control in controls)
{
    control.Dispose();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top