{"id":148,"date":"2014-06-01T00:38:50","date_gmt":"2014-05-31T22:38:50","guid":{"rendered":"http:\/\/dev.bratched.fr\/en\/utilisation-des-images-resources-avec-windows-phone\/"},"modified":"2019-07-20T17:42:58","modified_gmt":"2019-07-20T15:42:58","slug":"utilisation-des-images-resources-avec-windows-phone","status":"publish","type":"post","link":"https:\/\/bratched.com\/en\/2014\/06\/01\/utilisation-des-images-resources-avec-windows-phone\/","title":{"rendered":"Utilisation des Images resources avec Windows Phone"},"content":{"rendered":"<p>Je vous propose un petit retour d\u2019exp\u00e9rience sur l\u2019utilisation des ressources dans le d\u00e9veloppement Windows Phone dans un mod\u00e8le M-V-VM.<\/p>\n<h1>Diff\u00e9rentes fa\u00e7on de coder<\/h1>\n<p>L\u2019image que l\u2019on souhaite afficher provient des ressources et devrait pouvoir s\u2019afficher&nbsp;\u00e0 travers une propri\u00e9t\u00e9 Image de type BitmapImage dans un ViewModel. A noter que le dans l\u2019exemple ci dessous, UIThreadPool permet d\u2019afficher cette image m\u00eame lorsque celle-ci est aliment\u00e9e depuis un Thread qui tourne en t\u00e2che de fond.<\/p>\n<p><!-- Crayon Syntax Highlighter v2.6.1 --><\/p>\n<pre>SynchronizationContext UIThread = SynchronizationContext.Current;\n\npublic BitmapImage Image\n       {\n           get { return _image; }\n           set\n           {\n               UIThread.Post(_ =&gt;\n                   {\n                       _image = value;\n                       RaisePropertyChanged(\"Image\");\n                   }, null);\n           }\n       }<\/pre>\n<p><!-- [Format Time: 0.0032 seconds] --><\/p>\n<h1>Comment afficher une image incluse dans les ressources de l\u2019application&nbsp;?<\/h1>\n<p><span style=\"color: #ff0000\">Attention les 2 premi\u00e8res m\u00e9thodes d\u00e9crites sont \u00e0 proscrire et \u00e0 ne surtout pas reproduire<\/span>. Allez jusqu\u2019\u00e0 la fin de l\u2019article pour voir comment impl\u00e9menter correctement l\u2019affichage d\u2019une image ressource. <span id=\"more-624\"><\/span><\/p>\n<h2>M\u00e9thode Stream<\/h2>\n<p>Lorsque l\u2019on est habitu\u00e9 \u00e0 r\u00e9cup\u00e9rer une image d\u2019un flux http ou m\u00eame de l\u2019isolated Storage on peut \u00eatre tent\u00e9 d\u2019uniformiser le code et d\u2019impl\u00e9menter un Stream pour r\u00e9cup\u00e9rer l\u2019image stock\u00e9e dans&nbsp;une application :<\/p>\n<p><!-- Crayon Syntax Highlighter v2.6.1 --><\/p>\n<pre>public static void LoadResourceImage2(string resourceName, Action&lt;BitmapImage&gt; action)\n        {\n            var resource = Application.GetResourceStream(new Uri(resourceName, UriKind.Relative));\n            {\n                if (resource != null)\n                {\n                    Stream stream = resource.Stream;\n                    {\n                        if (stream != null)\n                        {\n                            Deployment.Current.Dispatcher.BeginInvoke(() =&gt;\n                            {\n                                StreamToBitmapAction(action, stream);\n                                stream.Dispose();\n                                stream = null;\n                            });\n                        }\n                        else\n                            throw new NullReferenceException();\n                    }\n                };\n            }\n        }<\/pre>\n<p><!-- [Format Time: 0.0065 seconds] --><\/p>\n<p>L\u2019affichage de l\u2019image&nbsp;est retourn\u00e9e par une m\u00e9thode g\u00e9n\u00e9rique qui prend un Stream en entr\u00e9e et&nbsp;retourne un BitmapImage en asynchrone dans une Action.<\/p>\n<p><!-- Crayon Syntax Highlighter v2.6.1 --><\/p>\n<pre>private static void StreamToBitmapAction(Action&lt;BitmapImage&gt; actionBitmap, Stream stream)\n        {\n            BitmapImage bitmapImage = new BitmapImage();\n            bitmapImage.CreateOptions = BitmapCreateOptions.None; \n            bitmapImage.SetSource(stream);\n            stream.Dispose();\n            if (actionBitmap != null)\n                actionBitmap(bitmapImage);<\/pre>\n<p><!-- [Format Time: 0.0033 seconds] --><\/p>\n<p>L\u2019utilisation de ce Stream peut ensuite se faire de la fa\u00e7on suivante&nbsp;:<\/p>\n<p><!-- Crayon Syntax Highlighter v2.6.1 --><\/p>\n<pre>CacheImageService.LoadResourceImage2(resourceName, b =&gt; Image = b ) ;<\/pre>\n<p><!-- [Format Time: 0.0011 seconds] --><\/p>\n<h2>M\u00e9thode async et await<\/h2>\n<p>Nous pouvons \u00e9galement utiliser async\/Await pour&nbsp;rendre le code plus compr\u00e9hensible et \u00e9viter ce meli-m\u00e9lo d\u2019actions imbriqu\u00e9es. A noter que le code&nbsp;peut \u00e9galement fonctionner avec Windows Phone 7 si vous ajoutez le paquet nuget Mycrosoft Async et que vous utilisez \u00e0 minima Visual Studio 2012 (<a title=\"Quelles versions de Visual Studio pour vos APPs Windows Phone ?\" href=\"http:\/\/dev.bratched.fr\/fr\/quelles-versions-de-visual-studio-pour-vos-apps-windows-phone\/\">donc avec Windows 8<\/a>). (Remarque : La version Visual Studio 2010 avec WP7 et le paquet Nuget Async&nbsp;semble fonctionner. Cependant l\u2019application&nbsp;se comportement de fa\u00e7on al\u00e9atoire avec le async\/await donc&nbsp;je vous recommande d\u2019\u00e9viter, sauf \u00e0 vouloir chercher durant des heures pourquoi votre application n\u2019ex\u00e9cute pas \u00e0 chaque fois le code async\/await). La version Visual Studio 2012 et WP7 fonctionne tr\u00e8s bien en revanche. Voici donc&nbsp;un exemple&nbsp;d\u2019impl\u00e9mentation possible avec le async await.<\/p>\n<p><!-- Crayon Syntax Highlighter v2.6.1 --><\/p>\n<pre>public static async Task&lt;BitmapImage&gt; LoadResourceImage1(string resourceName)\n        {\n            using (var imageStream = await LoadStreamResourceAsync(resourceName))\n            {\n                return await InitBitmapImageAsync(imageStream);\n\n            }\n            return null;\n        }\n\n        public static async Task&lt;Stream&gt; LoadStreamResourceAsync(string resourceName)\n        {\n\n            return await Task.Factory.StartNew&lt;Stream&gt;(() =&gt;\n            {\n                if (resourceName == null)\n                {\n                    throw new ArgumentException(\"Ressource Name is null\");\n                }\n                Stream stream = null;\n                var resource = Application.GetResourceStream(new Uri(resourceName, UriKind.Relative));\n                {\n                    if (resource != null)\n                        stream = resource.Stream;\n                }\n                return stream;\n            }, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);\n        }\n\n        private static async Task&lt;BitmapImage&gt; InitBitmapImageAsync(Stream imageStream)\n        {\n            BitmapImage image = null;\n            DispatcherSynchronizationContext dsc = new DispatcherSynchronizationContext(Deployment.Current.Dispatcher);\n            await Task.Factory.StartNew(() =&gt;\n            {\n                dsc.Send(_ =&gt;\n                {\n                    if (imageStream != null)\n                    {\n                        image = new BitmapImage();\n                        image.CreateOptions = BitmapCreateOptions.None;\n                        image.SetSource(imageStream);\n                    }\n                }, null);\n            });\n            return image;\n        }<\/pre>\n<p><!-- [Format Time: 0.0137 seconds] --><\/p>\n<h2>M\u00e9thode new BitmapImage<\/h2>\n<p>Enfin, la derni\u00e8re m\u00e9thode est d\u00e9concertante de simplicit\u00e9&nbsp;:<\/p>\n<p><!-- Crayon Syntax Highlighter v2.6.1 --><\/p>\n<pre> public static void LoadResourceImage3(string resourceName, Action&lt;BitmapImage&gt; action)\n        {\n        Uri uri = new Uri(resourceName, UriKind.RelativeOrAbsolute);\n        Deployment.Current.Dispatcher.BeginInvoke(() =&gt;\n            {\n                if (action != null)\n                    action(new BitmapImage(uri));\n            });            \n        }<\/pre>\n<p><!-- [Format Time: 0.0036 seconds] --><\/p>\n<p>Difficile de faire plus simple Non&nbsp;? Remarque : le \u201c<strong>Deployment.Current.Dispatcher.BeginInvoke<\/strong>\u201d est tr\u00e8s important ici pour pouvoir utiliser cette m\u00e9thode dans un Thread en arri\u00e8re plan : new BitmapImage n\u00e9cessite en effet le Thread principal de l\u2019interface utilisateur (le ThreadUI) pour s\u2019ex\u00e9cuter (l\u2019instruction \u2026Dispatcher\u2026&nbsp;est l\u00e0 pour indiquer que l\u2019ex\u00e9cution se fait dans le Thread principal).<\/p>\n<h1>Tests de performance<\/h1>\n<p><a class=\"grouped_elements\" href=\"http:\/\/dev.bratched.fr\/fr\/wp-content\/uploads\/sites\/2\/2014\/05\/wp_ss_20140530_0003.png\" rel=\"tc-fancybox-group624\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-626\" src=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/importedmedia\/blogmedia-wp-ss-20140530-0003-png.png\" alt=\"Capture Benchmark affichage ressource Image\" width=\"349\" height=\"581\"><\/a> Pour savoir laquelle de ces 3 m\u00e9thodes est la plus rapide, j\u2019ai r\u00e9alis\u00e9 un petite application&nbsp;Benchmark qui charge 100 images avec&nbsp;la r\u00e9partition&nbsp;suivante :<\/p>\n<ul>\n<li>50 images png petites (300\u00d7300 pour 25ko)<\/li>\n<li>50 images png grandes (1000\u00d71000 pour 437ko)<\/li>\n<\/ul>\n<p>Voici les r\u00e9sultats moyens observ\u00e9s sur un Nokia Lumia 920<\/p>\n<ul>\n<li>M\u00e9thode Stream avec async await&nbsp;: <span style=\"color: #ff0000\">5 secondes !<\/span><\/li>\n<li>M\u00e9thode Stream avec Action&nbsp;: 3,5 secondes<\/li>\n<li>M\u00e9thode new BitmapImage&nbsp;: <span style=\"color: #008000\">0,435 secondes&nbsp;! (10 x plus rapide)<\/span><\/li>\n<\/ul>\n<p>Cette petite application permet \u00e9galement de tester en r\u00e9el les images dans des listes de 100 \u00e9l\u00e9ments&nbsp;et ainsi&nbsp;d\u2019appr\u00e9cier l\u2019exp\u00e9rience utilisateur. <strong>La derni\u00e8re impl\u00e9mentation: \u201cnew BitmapImage(uri)\u201d, la plus simple, est&nbsp;\u00e0 privil\u00e9gier pour charger des ressources images car&nbsp;elle offre des performances sans \u00e9quivalent.<\/strong><\/p>\n<h1>Content ou resource ?<\/h1>\n<p>On retrouve pas mal d\u2019articles sur le stockage des ressources sous forme content ou resource. Tous les articles que j\u2019ai pu rencontrer recommandent de privil\u00e9gier le stockage de type \u00ab&nbsp;content&nbsp;\u00bb \u00e0 celui de type \u00ab&nbsp;resource&nbsp;\u00bb dans nos Apps.<\/p>\n<h2>Ressources \u201cContent\u201d<\/h2>\n<p><a class=\"grouped_elements\" href=\"http:\/\/dev.bratched.fr\/fr\/wp-content\/uploads\/sites\/2\/2014\/05\/VSResourceContent.png\" rel=\"tc-fancybox-group624\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-627\" src=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/importedmedia\/blogmedia-vsresourcecontent-png.png\" alt=\"Visual Studio Ressources Content\" width=\"308\" height=\"165\"><\/a> Les images stock\u00e9es avec une \u201cBuild Action\u201d = content sont simplement ajout\u00e9es au fichier xap de votre application, et de ce fait, ne sont pas stock\u00e9es dans la dll. Ces images&nbsp;sont accessibles directement par une syntaxe de cette forme \u00e0 travers&nbsp;une Uri : <strong>\u00ab&nbsp;Assets\/Testimage.png&nbsp;\u00bb<\/strong> (o\u00f9 <strong>Assets<\/strong> repr\u00e9sente le r\u00e9pertoire o\u00f9 elles sont stock\u00e9es).<\/p>\n<h2>Ressources \u201cResource\u201d<\/h2>\n<p><a class=\"grouped_elements\" href=\"http:\/\/dev.bratched.fr\/fr\/wp-content\/uploads\/sites\/2\/2014\/05\/VSResourceResource.png\" rel=\"tc-fancybox-group624\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-629\" src=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/importedmedia\/blogmedia-vsresourceresource-png.png\" alt=\"Visual Studio Ressource Resource\" width=\"299\" height=\"160\"><\/a> Les images avec un \u201cBuild Action\u201d =&nbsp;Resource sont stock\u00e9es directement dans la dll. Pour les utiliser, il faudra&nbsp;indiquer le chemin complet de cette dll&nbsp;de la fa\u00e7on suivante : <strong>\u201cSampleCacheImageApp;component\/Assets\/Testimage2_res.png\u201d<\/strong> (o\u00f9 <strong>SampleCacheImageApp<\/strong> repr\u00e9sente le nom de l\u2019application et&nbsp;<strong>\/Assets<\/strong> le r\u00e9pertoire) La resource \u00e9tant contenue dans la dll, il est alors normal que le chargement au d\u00e9marrage de la dll prenne un tout petit peu plus de temps.<\/p>\n<h2>Tests de performance<\/h2>\n<p>Les tests de performances sont assez troublants. Une premi\u00e8re phase de tests a \u00e9t\u00e9 r\u00e9alis\u00e9e avec l\u2019\u00e9mulateur qui a nettement favoris\u00e9 le&nbsp;stockage \u201cContent\u201d. Mais&nbsp;sur un vrai t\u00e9l\u00e9phone,&nbsp;les r\u00e9sultats sont totalement diff\u00e9rents :<\/p>\n<ul>\n<li>Rappel : M\u00e9thode new BitmapImage&nbsp;avec les images en&nbsp;\u00bb content&nbsp;\u00bb : 0,435 secondes&nbsp;!<\/li>\n<li>M\u00e9thode new BitmapImage avec image en \u00ab&nbsp;resource&nbsp;\u00bb&nbsp;: <span style=\"color: #008000\"><strong><span style=\"text-decoration: underline\">0,049 secondes !!!<\/span><\/strong>,<\/span> soit presque 10x plus rapide.<\/li>\n<\/ul>\n<p><a class=\"grouped_elements\" href=\"http:\/\/dev.bratched.fr\/fr\/wp-content\/uploads\/sites\/2\/2014\/05\/wp_ss_20140530_0002.png\" rel=\"tc-fancybox-group624\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-630\" src=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/importedmedia\/blogmedia-wp-ss-20140530-0002-png.png\" alt=\"Benchmark ressources buildaction content vs resource\" width=\"349\" height=\"581\"><\/a> Alors faut-il syst\u00e9matiquement utiliser des ressources en \u201cBuild Action =&nbsp;content&nbsp;\u201d&nbsp;? Personnellement, je viens de passer toutes mes ressources en \u201cAction Build = Resource\u201d&nbsp;pour toutes les listes n\u00e9cessitant des centaines de chargements\u2026 Si quelqu\u2019un peut me donner une explication&nbsp;\u00e0 cette diff\u00e9rence entre \u00e9mulateur et&nbsp;mat\u00e9riel? Ce chiffre est-il constat\u00e9 sur&nbsp;vos t\u00e9l\u00e9phones ? Ai-je commis une erreur dans l\u2019\u00e9criture des&nbsp;tests ? Est-ce li\u00e9 au nombre d\u2019applications install\u00e9es ? Le code source&nbsp;de l\u2019application&nbsp;des tests benchmark se trouvent \u00e0 cet emplacement : <a title=\"T\u00e9lecharger les sources\" href=\"http:\/\/1drv.ms\/1keBS7U\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" loading=\"lazy\" class=\"grouped_elements\" src=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/importedmedia\/blogmedia-download-10-icon-256-png.png\" alt=\"download-10-icon-256\" width=\"256\" height=\"256\"><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Je vous propose un petit retour d\u2019exp\u00e9rience sur l\u2019utilisation des ressources dans le d\u00e9veloppement Windows Phone dans un mod\u00e8le M-V-VM. Diff\u00e9rentes fa\u00e7on de coder L\u2019image que l\u2019on souhaite afficher provient des ressources et devrait pouvoir s\u2019afficher&nbsp;\u00e0 travers une propri\u00e9t\u00e9 Image de type BitmapImage dans un ViewModel. A noter que le dans l\u2019exemple ci dessous, UIThreadPool [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[273,276,278,280,299,314,317],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/148"}],"collection":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/comments?post=148"}],"version-history":[{"count":1,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/148\/revisions"}],"predecessor-version":[{"id":904,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/148\/revisions\/904"}],"wp:attachment":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/media?parent=148"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/categories?post=148"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/tags?post=148"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}