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

Windows Presentation Foundation Discussion :

WPF WrapPanel, Afficher une mosaïque d’image sans précharger les images invisibles


Sujet :

Windows Presentation Foundation

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 163
    Points : 120
    Points
    120
    Par défaut WPF WrapPanel, Afficher une mosaïque d’image sans précharger les images invisibles
    Bonjour à tous,

    J’ai un problème qui peut paraître simple. Je souhaite en effet reconstituer la vue «mozaïque de l’explorateur Windows», qui permet de visionner les miniatures des images d’un dossier.



    J’ai donc crée un WrapPanel dans un ScrollView. C’est un composant .Net WPF, similaire au Grid, ou un StackPanel, que je rempli de «Bloc Image» de 150 pixels au carré d’autant de fichier que j’ai dans mon dossier.

    Mais un soucis survient si j’ai beaucoup de fichiers. Admettons 1000. Charger 1000 fichier en mémoire, c'est beaucoup trop pour la mémoire. Ce que je souhaite, c’est donc dessiner 1000 cadre «Bloc Image» dans mon WrapPanel. Mais ne remplir d’images que ceux qui sont visibles, laissant les autres vides.

    Ainsi, je cherche à obtenir touts les WrapPanel.Children qui sont «visible», et les remplir. A chaque que fois que je scrolle, je charge mes images. Comme dans l'explorateur Windows.

    Comment les récupérer ces fameux blocs visibles à l'instant t dans mon WrapPanel ? Vous avez une idée ?

    Merci de votre aide.

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 163
    Points : 120
    Points
    120
    Par défaut
    Voici l'état actuel de mon programme :



    Ici les 1000 miniatures sont préchargés et prennent pratiquement 700 Mo en RAM... alors qu'il serait bien plus judicieux de ne charger que les 9 qui sont visibles.

  3. #3
    Membre expert
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 2 210
    Points : 3 015
    Points
    3 015
    Par défaut
    Salut,

    Le conteneur WrapPanel ne supporte pas la virtualisation. Il existe des implémentations :


    Sinon tu dis mettre un WrapPanel dans un ScrollViewer. Tu peux aussi utiliser une ListBox dont tu redéfinis l'ItemsPanel (voir cet article de Josh Smith). Dans le cas où, bien sûr, tu aurais besoin des avantages d'une ListBox (comme par exemple la sélection d'un des items, ...)

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 163
    Points : 120
    Points
    120
    Par défaut
    Merci pour les liens. Il faut au moins une bonne journée pour commencer à appréhender la chose. Je vais m'y mettre.

    Aussi, tu me proposes une ListBox, mais est-ce qu'elle est Virtualisée, ou c'est juste pour la sélection ?

  5. #5
    Membre éprouvé Avatar de obito
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2008
    Messages
    773
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2008
    Messages : 773
    Points : 948
    Points
    948
    Par défaut
    Salut,

    je pense que ce post va t'interesser (surtout le dernier post) :

    http://social.msdn.microsoft.com/for...c-b58672c467a4
    ►Ne pas oublier le

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 163
    Points : 120
    Points
    120
    Par défaut
    Citation Envoyé par obito Voir le message
    Salut,

    je pense que ce post va t'interesser (surtout le dernier post) :

    http://social.msdn.microsoft.com/for...c-b58672c467a4
    Je viens de tester ton exemple, cela voudrait il dire que le binding de la listbox permet de ne charger en mémoire que les éléments qui sont visible dans le cadre d'affichage de cette listbox ???

  7. #7
    Membre expert
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 2 210
    Points : 3 015
    Points
    3 015
    Par défaut
    Citation Envoyé par nicopulse
    Aussi, tu me proposes une ListBox, mais est-ce qu'elle est Virtualisée, ou c'est juste pour la sélection ?
    En fait, dans l'article de Josh Smith, tu peux voir ce code :
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <Setter Property="ItemsPanel">
      <Setter.Value>
        <ItemsPanelTemplate>
          <WrapPanel />
        </ItemsPanelTemplate>
      </Setter.Value>
    </Setter>

    Toi, il faudra, si tu décides d'utiliser une ListBox, remplacer le WrapPanel classique par un WrapPanel supportant la virtualisation.

    Par défaut, la ListBox utilise un VirtualizingStackPanel.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 163
    Points : 120
    Points
    120
    Par défaut
    Citation Envoyé par binoo Voir le message
    Salut,

    Le conteneur WrapPanel ne supporte pas la virtualisation. Il existe des implémentations :


    Sinon tu dis mettre un WrapPanel dans un ScrollViewer. Tu peux aussi utiliser une ListBox dont tu redéfinis l'ItemsPanel (voir cet article de Josh Smith).

    Citation Envoyé par binoo Voir le message
    En fait, dans l'article de Josh Smith, tu peux voir ce code :
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <Setter Property="ItemsPanel">
      <Setter.Value>
        <ItemsPanelTemplate>
          <WrapPanel />
        </ItemsPanelTemplate>
      </Setter.Value>
    </Setter>

    Toi, il faudra, si tu décides d'utiliser une ListBox, remplacer le WrapPanel classique par un WrapPanel supportant la virtualisation.

    Par défaut, la ListBox utilise un VirtualizingStackPanel.

    J'ai exactement suivi tes conseils en utilisant l'implémentation VirtualizingWrapPanel + la ListBox de Josh Smith. Ca donne ça dans le XAML :

    Code XML : 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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    <UserControl x:Class="check_e.BlocImages"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:check_e"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
     
     
        <UserControl.Resources>
            <Style TargetType="{x:Type ListBox}">
                <!-- Set the ItemTemplate of the ListBox to a DataTemplate 
               which explains how to display an object of type BitmapImage. -->
                <Setter Property="ItemTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <local:BlocImage ImageChemin="C:\imga.jpg">
     
                            </local:BlocImage>
                            <!-- <Border  BorderBrush="Black" BorderThickness="4" CornerRadius="5" Margin="6"> --> 
                                 <!-- <Image  Source="{Binding Path=UriSource}" Stretch="Fill" Width="100" Height="120"  /> -->
                      <!-- </Border> -->
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
     
                <!-- Swap out the default items panel with a WrapPanel so that
               the images will be arranged with a different layout. -->
                <Setter Property="ItemsPanel">
                    <Setter.Value>
                        <ItemsPanelTemplate>
                            <local:VirtualizingWrapPanel />
                        </ItemsPanelTemplate>
                    </Setter.Value>
                </Setter>
     
                <!-- Set this attached property to 'Disabled' so that the 
               ScrollViewer in the ListBox will never show a horizontal 
               scrollbar, and the WrapPanel it contains will be constrained 
               to the width of the ScrollViewer's viewable surface. -->
                <Setter 
            Property="ScrollViewer.HorizontalScrollBarVisibility" 
            Value="Disabled" 
            />
            </Style>
        </UserControl.Resources>
     
        <UserControl.DataContext>
            <ObjectDataProvider 
                ObjectType="{x:Type local:ImageLoader}"  
                MethodName="LoadImages" 
          />
        </UserControl.DataContext>
     
        <ListBox Name="_wrapPanel" ItemsSource="{Binding}" >
            <ListBox.Background>
                <ImageBrush ImageSource="/check-e;component/background.png" TileMode="Tile" ViewportUnits="Absolute" Viewport="0,0,4,4" />
            </ListBox.Background>
        </ListBox>
     
    </UserControl>

    J'arrive pratiquement à une implémentation satisfaisante, sauf que j'ai un dernier (j'espère) soucis.
    L'erreur à l'execution, survient au niveau de la définition de l'ItemTemplate de la liste (soit le bloc contenant une image) :

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     <Setter Property="ItemTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <local:BlocImage ImageChemin="{Binding Path=FullName}">
     
                            </local:BlocImage>
                            <!-- <Border  BorderBrush="Black" BorderThickness="4" CornerRadius="5" Margin="6"> --> 
                                 <!-- <Image  Source="{Binding Path=UriSource}" Stretch="Fill" Width="100" Height="120"  /> -->
                      <!-- </Border> -->
                        </DataTemplate>
                    </Setter.Value>
                </Setter>

    Comme tu le vois j'ai remplacer le "bloc avec un border", par un UserControl (BlocImage) que j'ai définie moi même dans mon namespace courant (local).

    Sauf qu'a l'execution, j'ai une erreur du type
    L'objet ne peut être 'binding' car il n'est pas une DependencyProperty d'un DependencyObject
    J'ai l'impression que l'erreur vient de me ma propriété "ImageChemin" de mon BlocImage .... Il ne faut pas rajouter un truc pour le binding ?

  9. #9
    Membre expert
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 2 210
    Points : 3 015
    Points
    3 015
    Par défaut
    Citation Envoyé par nicopulse
    J'ai l'impression que l'erreur vient de me ma propriété "ImageChemin" de mon BlocImage .... Il ne faut pas rajouter un truc pour le binding ?
    Si, il faut que cette propriété soit, comme le message le dit le mesage, une DependencyProperty.

    Code c# : 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
        public string ImageChemin {
          get { return (string)GetValue(ImageCheminProperty); }
          set { SetValue(ImageCheminProperty, value); }
        }
     
        public static readonly DependencyProperty ImageCheminProperty =
                               DependencyProperty.Register(
                               "ImageChemin",
                               typeof(string),
                               typeof(BlocImage),
                               new FrameworkPropertyMetadata(null, new PropertyChangedCallback(ImageCheminPropertyChanged))
                               );
     
        public static void ImageCheminPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
          BlocImage ctrl = d as BlocImage;
          if (ctrl != null) {
            string strChemin = e.NewValue as string;
     
            if (!string.IsNullOrEmpty(strChemin)) {
              // Utilisation de la variable pour affecter la source de l'image
     
            }
          }
        }

Discussions similaires

  1. Afficher une page struts sans form
    Par charles888 dans le forum Struts 1
    Réponses: 2
    Dernier message: 13/03/2012, 11h08
  2. Afficher une nouvelle fenetre sans changer la page
    Par ahmedmido dans le forum SharePoint
    Réponses: 0
    Dernier message: 06/08/2008, 17h10
  3. Obtenir de xslt qu'il affiche une variable php sans l'interpréter
    Par Dendrite dans le forum XSL/XSLT/XPATH
    Réponses: 16
    Dernier message: 15/07/2008, 11h51
  4. [WPF] cacher/afficher une window
    Par maa dans le forum Windows Presentation Foundation
    Réponses: 8
    Dernier message: 09/01/2008, 22h41
  5. afficher une page web sans la barre d'adresse
    Par bif5 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 24/11/2005, 18h21

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