Que sont les fenêtres de stationnement dans Winforms?

Il s’agit d’une question complémentaire à cette réponse https://stackoverflow.com/a/20584601/2530848 .

J’avais l’impression que Control classe de Control n’implémente pas finailzer, ce qui est vrai, de sorte que les Control non étanches fuient à jamais et ne sont pas nettoyés lors de la finalisation.

Hans Passant donne un indice dans la section commentaires en disant que ParkingWindow , et quelques mots clés ParkingWindow . J’ai cherché sur Google avec ce mot clé, je ne trouve aucune ressource utile à ce sujet.

Enfin, j’ai trouvé une classe nommée ParkingWindow dans System.Windows.Forms.Application.ParkingWindow via le décompilateur, je n’arrive pas à comprendre ce qui est fait avec cela.

Il semblerait que des fenêtres sans parent soient associées à cette fenêtre de stationnement et soient détruites plus tard à un moment donné, mais sans certitude.

La question est: Qu’est-ce que ParkingWindow et à quoi sert-il?

Edit: Comment cela est-il lié à la finalisation ou au nettoyage du contrôle?

et détruit plus tard à un moment donné, mais pas sûr

Ce “pas sûr” est le noeud du problème. Cela ne va pas très souvent avec la fenêtre ne soit pas détruite du tout.

Le billet de blog de Shawn Farka explique bien l’intention initiale de Parking Window. La dépense de devoir recréer les fenêtres enfants était certainement en tête de liste. Cependant, certains types de fenêtres enfants sont très difficiles à reproduire avec précision. Une TreeView est un bon exemple, elle est plutôt associée à un état d’exécution. Pour le faire avec précision, vous devez enregistrer l’état de réduction de chaque nœud. C’est douloureux et Winforms ne le fait pas. Lorsque vous réaffectez, par exemple, les propriétés CheckBoxes ou StateImageList, vous constaterez que tout va mal.

Dans l’ensemble, c’est un bon tour, mais ils ont exagéré. Un contrôle enfant ne se termine pas (temporairement) sur la fenêtre Parking lorsque la fenêtre parent est recréée, il y est également déplacé lorsque:

  • vous définissez sa propriété Parent sur null
  • vous utilisez la méthode Remove / At () de la collection Controls du parent
  • vous utilisez la méthode Clear () de la collection Controls du parent

En particulier, les deux dernières puces sont presque toujours mortelles dans un programme Winforms typique. Ils ont tendance à être utilisés lorsque le programmeur ajoute et supprime dynamicment des contrôles au moment de l’exécution. Le problème est que le contrôle est ré-hébergé sur la fenêtre de stationnement, mais le programmeur les oublie tout simplement, perdant ainsi la référence au contrôle. Et ils vivront là pour toujours . Jusqu’à ce que l’utilisateur termine le programme, car il se transforme en mélasse lente en raison de la création de milliers de fenêtres. Ou le programme se bloque avec “Erreur lors de la création du descripteur de fenêtre”. Ce qui se produit lorsque Windows devient sulky après que le programme a créé 10 000 fenêtres.

Au lieu de cela, il est nécessaire d’appeler la méthode Dispose () du contrôle. Très inhabituel dans .NET en général, appeler Dispose () est toujours facultatif. Pas dans le cas de la classe Control, la fenêtre Parking conserve une référence sur le contrôle et empêche ainsi le finaliseur de s’exécuter.

Ceci est couvert dans cet article par Shawn Burke de MS: Windows Forms Parking Window .

L’un de nos objectives avec Windows Forms était d’essayer de dissiper au maximum les bizarreries de Win32. Et l’une des principales bizarreries est celle de la gestion et de la durée de vie des descripteurs de fenêtres (HWND). Nous ne voulions certainement pas que l’utilisateur moyen ait à s’inquiéter de ce genre de choses. Dans la plupart des cas, c’était assez facile. Vous venez de rassembler tout l’état, puis lorsque vous avez besoin d’afficher la fenêtre, vous effectuez la création à la demande, puis vous éloignez votre état du HWND au lieu de vos membres internes.

Eh bien, cela ne fonctionne pas toujours si bien. Vous voyez, certaines propriétés des fenêtres Win32 ne peuvent pas être modifiées une fois la fenêtre créée. Comme le style de la bordure, par exemple. Ainsi, pour permettre à un utilisateur de modifier le style de la bordure après la création de la fenêtre, vous devez recréer le descripteur. Ce qui signifie que vous devez non seulement extraire tout l’état souhaité de l’existant, mais également le recréer et le réintroduire. D’accord, ce n’est pas trop difficile.

Mais qu’en est-il des enfants? Oh, les fiddlesticks. Les enfants.

Si la fenêtre sur laquelle vous modifiez la bordure a des enfants, la destruction de sa poignée détruira également les poignées de tous ses enfants. Ensuite, vous devez les recréer, ce qui coûte très cher. Et cher c’est mauvais.

Entrez dans la fenêtre de stationnement. La fenêtre de stationnement était notre solution à ce problème. C’était quelque part que vous pouviez “garer” les HWND jusqu’à ce que vous ayez un parent qui leur convient. Voyez-le comme une poignée de fenêtre, mais invisible.

Donc, dans le cas d’une recréation de pseudonyme, nous vérifierions s’il y avait des enfants. S’il y en avait une, nous créerions (si nécessaire) la fenêtre de stationnement, parentions les enfants à celle-ci, recréerons le descripteur du parent, puis les replacerions. Cela a bien fonctionné, bien que la gestion de la durée de vie de la fenêtre de stationnement ait posé quelques problèmes …