Déjà, juste le titre, ça calme bien. Un peu autant que le temps que j’ai passé à trouver la solution en fait.

Voici donc le problème : J’ai un wrap panel en WPF qui sert d’ItemPanel à une ListBox. Jusque là on ne se fatigue pas trop non plus:

<ListBox ItemsSource="{Binding}" x:Name="imagesList">
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <WrapPanel>
                            </WrapPanel>
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                </ListBox>

Toutefois, lorsque je veux binder une grosse liste d’images (plus de 300) en provenance de ma base de données à ma ListBox, je me récupére en supplément un bon gros lag car le gentil Wrap Panel ne sait pas virtualiser ses items et doit donc tous les créer pour s’afficher (contrairement par exemple à une ListView qui saura ne construire que les items qu’elles affichent en temps réel).

Donc, je me suis lancé à la recherche d’une solution qui me permettrait d’asynchroniser le remplissage de mon Wrap panel.

Première idée, on met benoitement notre imagesList.DataContext = maListe dans un ThreadPool.QueueUserWorkItem. Et là c’est le drame car WPF me bloque comme j’essaye d’accéder à un DispatcherObject depuis un autre thread que celui qui a servit à construire le contrôle.

La solution est un tantinet plus ardue:

Premièrement, il faut modifier notre objet qui porte l’image à afficher pour lui ajouter une propriété supplémentaire de type BitmapFrame (qui a l’énorme avantage de ne pas vérifier l’origine du thread appelant). Il est ici important de ne pas laisser le BitmapFrame se mettre en DelayLoad depuis le cache d’image d’ou l’utilisation du paramètre BitmapCacheOption.OnLoad:

    public partial class Card
    {
        BitmapFrame bitmapImage;

        public BitmapFrame Bitmap
        {
            get
            {
                return bitmapImage;
            }
        }

        public void GenerateBitmap()
        {
            if (bitmapImage != null)
            {
                return;
            }
            using (MemoryStream ms = new MemoryStream(Image))
            {
                bitmapImage = BitmapFrame.Create(ms, BitmapCreateOptions.None, 
BitmapCacheOption.OnLoad); } } }

Deuxièmement, avant d’affecter le DataContext de notre ListBox, nous allons appeler de manière asynchrone sur chacun de nos objets la méthode GenerateBitmap.

Finalement, il suffit de faire un petit Dispatcher.Invoke pour affecter notre DataContext:

ThreadPool.QueueUserWorkItem(o =>
          {
            foreach (Card card in list)
            {
               card.GenerateBitmap();
            }
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(()=>
            {
               imagesList.DataContext = source;
            }));
});

Le résultat fait plaisir à voir je vous l’assure :)

J’ai eu plusieurs fois la question : Maiiiiiis pourquoi WPF ne gère pas le double clic!!! C’est trop nul WPF.
Alors en fait oui mais non. Effectivement il n’y a pas un événement qui s’appelle “MouseDoubleClick”. Toutefois le double clic est bien géré ma bonne dame!

Et c’est même plutôt bien gérer. Car après tout, que se passerait-il si je voulais un MouseTripleClick? Il faudrait que je chiale auprès de l’équipe de développement de WPF ?

Alors pour couper court à ce suspens insoutenable, voici la solution : Abonnez vous à l’événement MouseDown (par exemple) et regarder le gentil paramètre MouseButtonEventArgs qui vous est fait passé. Notez surtout la propriété ClickCount. Et paf miracle:) Cette petite propriété gère le double clic (et plus) pour nous!

Un exemple en direct:

private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.ClickCount == 2)
    {
        if (FullImage.Visibility == Visibility.Hidden)
            FullImage.Visibility = Visibility.Visible;
        else
            FullImage.Visibility = Visibility.Hidden;
    }
}

 

Et voilou…

A la demande générale, la Bewise Day Conference est de retour pour une 4ème édition ! Encore une fois, venez découvrir ce qui se fait de mieux dans les technologies Microsoft.

Cette année, beaucoup de nouveautés, puisque Microsoft lance la gamme 2010 de ses produits, notamment Visual Studio, Sharepoint, mais aussi la version 4.0 de son framework .Net, MVC 2, Azure, Silverlight 4 et bien d’autres choses bien croustillantes.

J’animerai les plénières cette année et je vous conseille d’y participer car vous y découvrirez le grand secret de Bewise :).

Pour les inscriptions, rendez-vous sur le site officiel de la BDC 2010.

kosh 13. février 2009, 01:14

Et voila, les TechDays 2009 sont finis. Ce fut une fois de plus un superbe événement ou j’ai eu beaucoup de plaisir à animer 3 sessions. Je pense notamment à ma session Coding For Fun avec mon camarade Mitsu Furuta ou l’on s’est bien amusé.

Pour ceux qui souhaitent retrouver les présentations et tout le code des démos, c’est par ici que ca se passe.

kosh 4. février 2009, 10:34

Petite pub pour mes sessions aux TechDays 2009:

 DirectX10 pour les Windows Formstdspeakermsfv9

 Nouveautés de WPF 3.5 SP1

 Coding4Fun

 

Comme toujours mes sessions sont très orientées 3D et présentation. Nous parlerons donc de DirectX10, de pixels shaders et avec Mitsu nous vous montrerons que l’on peut s’amuser avec des petites applications “ludiques” ;)

Après avoir installé le SDK de Windows 7, il y a de très grandes chances que l’intellisense ne marche plus sous Visual Studio 2008 au niveau de WPF.

Pour résoudre ce petit soucis (lié à la modification d’une clé de registre par l’installeur du Windows SDK), il suffit de taper cette ligne de commande:

 

regsvr32 "%CommonProgramFiles%\Microsoft Shared\MSEnv\TextMgrP.dll"

 

Fermez pluis relancez Visual Studio et l’intellisense est de retour :).

Kosh 18. avril 2008, 13:32

La BDC 2008 est terminée et fût un grand succès. Vous pouvez retrouver sur ces adresses les sessions que j'ai animé:

http://silverlight.services.live.com/invoke/58450/BDC%202008%20Session%20Pl%c3%a9ni%c3%a8re%201/iframe.html

http://silverlight.services.live.com/invoke/58450/BDC%202008%20Session%20Pl%c3%a9ni%c3%a8re%202/iframe.html

http://silverlight.services.live.com/invoke/58450/BDC%202008%20Session%20Pl%c3%a9ni%c3%a8re%203/iframe.html

http://silverlight.services.live.com/invoke/58450/BDC%202008%20Session%20Pl%c3%a9ni%c3%a8re%204/iframe.html

http://silverlight.services.live.com/invoke/58450/BDC%202008%20Session%20NIU1/iframe.html

http://silverlight.services.live.com/invoke/58450/BDC%202008%20Session%20NIU2/iframe.html

Ne vous inquiétez pas si la page reste blanche un moment, c'est lié au chargement du contrôle Silverligth 1.0.

Et hop la:)

Kosh 2. avril 2008, 21:38

Si vous n'avez pu assister à mes sublimes sessions aux TechDays 2008, vous pouvez désormais les consulter en Webcasts aux adresses suivantes:

 

Have fun.

Un nouvel article sur WPF et plus particulièrement sur les dependency properties et leur fonctionnement.

Téléchargements:

Lorsque l'on veut faire de la 3D avec WPF il n'est pas forcément nécessaire de positionner des lumières pour voir les objets 3D. En effet, seule la caméra est nécessaire.

Un objet 3D peut être auto-éclairé en utilisant des matériaux émissifs. Toutefois et contrairement à ce que l'on rencontre par ailleurs, il est obligatoire de positionner un matériau de diffuse même si aucune lumière n'est présente (en effet, le matériau de diffuse donne la couleur de l'objet par rapport aux lumières).

Un viewport3D minimal sans lumière donne donc:

<Viewport3D ClipToBounds="True">
      <Viewport3D.Camera>
        <PerspectiveCamera Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" FarPlaneDistance="100" NearPlaneDistance="0" />
      </Viewport3D.Camera>
      <Viewport3D.Children>
        <ModelVisual3D>
          <ModelVisual3D.Content>
            <GeometryModel3D>
              <GeometryModel3D.Geometry>
                <MeshGeometry3D
                TriangleIndices="0,1,2 3,4,5 "
                Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "
                TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 "
                Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " />
              </GeometryModel3D.Geometry>
              <GeometryModel3D.Material>
                <MaterialGroup>
                  <DiffuseMaterial Brush="Black">
                  </DiffuseMaterial>
                  <EmissiveMaterial Brush="Red">
                  </EmissiveMaterial>
                </MaterialGroup>
              </GeometryModel3D.Material>
            </GeometryModel3D>
          </ModelVisual3D.Content>
        </ModelVisual3D>
      </Viewport3D.Children>
    </Viewport3D>

 

On se retrouve donc avec l'obligation de mettre un MaterialGroup afin d'ajouter notre matériau émissif couplé à un matériau de diffuse noir.