IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Silverlight Discussion :

Instanciations multiples de contrôles dans Silverlight


Sujet :

Silverlight

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    68
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Novembre 2007
    Messages : 68
    Par défaut Instanciations multiples de contrôles dans Silverlight
    Je vais exposer ci-après une situation pour laquelle je requière les lumières de quiconque voudra bien y 'perdre' un peu de temps.

    Il me semble que la problèmatique exposée ci-après relève d'un niveau expert. Je m'efforce de l'exposer le plus clairement possible en espérant que cela ne sera pas trop confus.

    L'exemple présenté ci après n'est pas tiré d'une situation réelle, mais à simplement été construit pour mettre en lumière un point qui me semble très étrange, et qui me pose problème. Je me dis que peut être la solution est évidente mais que je tourne trop en rond depuis un moment pour la voir.

    Voici le XAML d'une page suivi de son code behind :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <UserControl x:Class="SilverlightApplication1.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <StackPanel x:Name="pnlTest">
            </StackPanel>
            <Button Click="Button_Click" Content="Test" />
        </StackPanel>
    </Grid>
    </UserControl>
    
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
     
    namespace SilverlightApplication1
    {
    publicpartialclassPage : UserControl
    {
        public Page()
        {
            InitializeComponent();
        }
     
        privatevoid Button_Click(object sender, RoutedEventArgs e)
        {
            //---> On vide le stackpanel. En effet, si ce n'est pas le
            // premier click sur le bouton, le stackpanel contient d‚j…
            // un UserControlTest
            pnlTest.Children.Clear();
            //---> Instanciation d'un UserControlTest
            var uc = newUserControlTest(); 
            //---> On le place dans le stackpanel
            pnlTest.Children.Add(uc);
        }
    }
    }
    
    Voici le XAML du UserControl utilisé dans la page, suivi de son code behind :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <UserControl x:Class="SilverlightApplication1.UserControlTest"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock Text="Text de test" />
    </Grid>
    </UserControl>
    
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
     
    namespace SilverlightApplication1
    {
    publicpartialclassUserControlTest : UserControl
    {
        //---> Ce champ static sert juste de compteur afin
        // d'identifier les diff‚rentes instance de UserControlTest
        // En effet, a la cr‚ation, le num‚ro d'instance sera plac‚ dans
        // le DataContext
        privatestaticint Nb = 0;
        public UserControlTest()
        {
            InitializeComponent();
            //---> On affecte le num‚ro d'instance
            this.DataContext = Nb;
            Nb++;
            //---> On s'abonne … l'‚vŠnement LayoutUpdated
            this.LayoutUpdated += newEventHandler(UserControlTest_LayoutUpdated);
        }
     
        void UserControlTest_LayoutUpdated(object sender, EventArgs e)
        {
            //---> Placer un point d'arret ici, afin de suivre les appels … cet ‚vŠnement
            //---> Ajouter un espion sur this.DataContext afin de suivre quelle instance est en cours
        }
    }
    }
    Maintenant, passons aux explications :

    Le code ci-dessus parrait on ne peut plus simple. Une Page avec un Button. On Click sur le Button et une instance d'un UserControlTest est crée puis placée dans un StackPanel.

    Ce Click peut être effectuée autant de fois que voulu. C'est pour cette raison que le StackPanel est préalablement vidé via Clear() afin de garantir qu'il ne contienne qu'une seule instance de UserControlTest à la fois.

    Après plusieurs Click sur le Button, on s'attend à ce qu'une seule instance du UserControlTest soit présente dans le StackPanel et participe à la 'vie' de la Page. En testant, c'est bel et bien ce qui se passe sur le plan visuel.

    Et bien en fait, le code ci-dessus montre que ce n'est pas vraiment le cas. Pour vous aider à identifier les instances de UserControlTest en cause, un Id est placé dans le DataContext. Ainsi, via un simple espion dans le debogueur il est aisé d'identifier en permanence sur quelle instance le code s'applique.

    Vous ne serez pas surpris de constater que même après le Clear(), les instances précédentes de UserControlTest ne sont pas dédruites mais qu'elles persistent toujours bel et bien en mémoire. En effet, le Clear() supprime le UserControlTest de la collection Children du StackPanel, le supprime donc à priori de l'arboressance visuel.

    Pourtant, lorsque l'on suit les appels effectués à UserControlTest_LayoutUpdated, on constate que toutes les instances de UserControlTest (qu'elles soient encore dans le StackPanel ou non) continue de répondre à l'évènement LayoutUpdated et donc de participer à la vie de la Page.

    Quand on y réfléchis, cela peut sembler logique. En effet, l'objet est abonné à l'évènement et toujours instancié. Mais comment se fait-il que un UpdateLayout ait-lieu sur un contrôle qui n'est plus dans l'arboressance visuelle ?

    En tous les cas, il semblerait logique de pouvoir se désabonner à l'évènement. De plus, libérer l'instance serait utile. Mais, 1) Le destructeur n'est pas appelé 2) Même en implémentant IDisposable, la méthode Dipsose n'est pas appelée 3) Il n'y a pas d'évènement UnLoaded

    Question : comment le contrôle peut-il se tenir informé de sa vie au sein de l'arboressance visuelle des contrôles ?

    Problèmatique n°1

    Je m'intérroge quand aux performances et à la mémoire. Après plusieurs centaines d'instanciations, le phénomène devient inquiétant. La moindre modification au niveau UI déclanche des centaines d'appels inutiles et suceptibles d'engendrer des bogues sur UpdatedLayout.

    Problématique n°2

    L'explication suivante semble faire apparaitre que ce problème dépasse le simple contexte lié aux évènements.

    Imaginez mainteant que vous souhaitiez créer un contrôle du type PopupButton. C'est à dire un Button qui ouvre un Popup lors du click. Le contenu de ce Popup pouvant être défini selon les besoins. Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    <PopupButton Content="Cliquez ici">
         <Button x:Name="btActionA" Content="Action A"/>
         <Button x:Name="btActionB" Content="Action B"/>
         <Button x:Name="btActionC" Content="Action C"/>
    </PopupButton>
    Lorsque l'on Click sur le Button, on veut voir le Popup s'ouvrir et contenir les trois Button d'action précédents. Ces trois Button sont nommés car référencés dans le code (pour activation / désactivation en fonction du context par exemple). A vous d'imaginez ce qui vous voulez. Le principal ici c'est que 1) PoupButton est un ContentControl dont le Template est défini dans generic.xaml 2) Il contient des contrôles nommés.

    On peut alors utiliser ce PopupButton dans des UserControl pour par exemple créer différents ecrans de saisie qui seront instanciés selon les besoins au cours de l'application. Ces différents UserControl pourront par exemple être instanciés exactement de la même façon que dans l'exemple de page ci-dessus, pour être ensuite placés par exemple dans un StackPanel.

    Le problème, c'est que tout se passe bien lors de la première instanciation. Mais dès la seconde, une erreur se produit signalant que les noms utilisés sont déjà utilisés dans la page.

    Je précise pour compliquer, que ce message ne survient que si les contrôles nommés sont placés dans un contrôl Popup. Si l'on remplace le Popup par un StackPanel, le phénomène des appels aux objets qui ne font plus parti de l'arboressance visuelle persiste, mais il n'y a pas de message d'erreur.

    Merci d'avance d'avoir lu ce message jusqu'ici

  2. #2
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Par défaut
    Salut,

    Pour ton problème numéro il semblerait vraisemblablement d'un bug.
    Une solution serait d'appeler manuellement ton GC (même si je ne suis pas fan de cette méthode).
    Une autre solution serait de te désabonner de tous tes évènements lorsque le Parent de ton objet est à null.

    Je t'invite à poster sur le forum Bug de Silverlight.net pour voir si oui ou pas il s'agit d'un bug.

    http://silverlight.net/forums/28.aspx

    Pour ta problématique numéro 2, je n'ai malheureusement pas compris.

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    68
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Novembre 2007
    Messages : 68
    Par défaut
    Merci pour cette réponse.

    Pour ce qui est de se désabonner quand le parent est à null :
    1) En WPF il n'y a pas de problème à faire cela. En Silverlight je n'ai trouvé aucun moyen d'être informé de ce genre de changement.
    2) Ce n'est pas forcément le parent du contrôl qui est à null. Le contrôle peut être sorti de l'arboressance parceque un parent loingtain est sorti de l'arboressance. Alors qui lui même est toujours lié à son parent.

Discussions similaires

  1. Problème d'instanciation multiple de static dans dll
    Par fredoule2k dans le forum Langage
    Réponses: 7
    Dernier message: 10/10/2009, 13h56
  2. Réponses: 2
    Dernier message: 13/10/2004, 15h32
  3. [VB6] sélection multiple de colonne dans excel grâce à VB
    Par biquet dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 02/08/2004, 12h44
  4. Ajouter des contrôles dans la palette des contrôles.
    Par WOLO Laurent dans le forum MFC
    Réponses: 4
    Dernier message: 22/01/2004, 08h27
  5. Création multiple table paradox dans le code
    Par scarabee dans le forum C++Builder
    Réponses: 8
    Dernier message: 30/10/2002, 10h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo