Je suis en train de faire le sample pour coder les morceaux importants ici (me suis battu toute la nuit avec XmlRpc pour répondre à d'autres threads qui en parlaient )
Je suis en train de faire le sample pour coder les morceaux importants ici (me suis battu toute la nuit avec XmlRpc pour répondre à d'autres threads qui en parlaient )
Ma réponse vous a aidé ? Pensez à voter pour elle. N'oubliez pas non plus de changer le statut de votre thread en Résolu.
Mon blog
Ma société: So@t
C'est le control Image en lui même qui s'en charge.
Dans le Source="{Binding Path=Image}" ; Image correspond à l'url de l'image.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 <Image Source="{Binding Path=Image}" Height="101" HorizontalAlignment="Left" Margin="7,3,0,0" x:Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="132" > </Image>
ok,
donc je te propose de créer une variable dans ta page comme suit:
et dans ta boucle tu fais comme ça:
Code : Sélectionner tout - Visualiser dans une fenêtre à part Bool Downloading = false;
Ensuite dans ton évènnement OpenReadCompleted tu ajoutes ça:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 while (j < listImage.Count) { if(!Downloading) { Downloading = true; SauvegardeImageInfoIS(listImage[j]); j++; } }
De cette manière ta boucle passera à l'image suivante que lorsque l'image en cours de téléchargement sera enregistrée etc....
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 void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { // Read complete int count; byte[] buffer = new byte[2048]; Debug.WriteLine("Image Acquisition Complete"); // Create (or replace) file and write image to it Stream stream = e.Result; using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication()) { using (System.IO.IsolatedStorage.IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(ImagePath, FileMode.Create, isf)) { count = 0; while (0 < (count = stream.Read(buffer, 0, buffer.Length))) { isfs.Write(buffer, 0, count); } stream.Close(); isfs.Close(); } } Downloading=false; Debug.WriteLine("Image Saved"); }
tiens moi au courant si cela te convient
La Théorie c'est quand on comprends tout mais que rien ne fonctionne.
La Pratique c'est quand tout fonctionne mais qu'on ne sait pas pourquoi !
Si vous aimez ma réponse, cliquez sur la main verte Merci
Bon, me revoilà. J'ai attendu de faire un maximum de tests avant de pouvoir apporter cette réponse. (J'écrirai un article à ce sujet, le temps de remettre au propre). J'ai aussi eu bcp de boulot à côté d'ou ma réponse tardive.
La méthode de DotNET74 est bonne, mais, il va manquer quelques petites choses quand même (^_^).
Il va te falloir déjà 2 méthodes spécifiques pour tes images : 1 qui sauvegarde, l'autre qui lit le flux pour être bindé à l'image.
Pourquoi ?
La sauvegarde, c'est parce que c'est ce que tu veux faire . Ensuite, la lecture?
L'image est sauvegardée dans l'IsolatedStorage, donc, il va te falloir la lire dans l'IsolatedStorage. Tu ne pourras pas la lire de façon classique, ni simplement te contenter t'indiquer son chemin.
Ta méthode de lecture doit te renvoyer un BitmapImage que tu binderas à ton Image.
Attention à ne jamais binder ta liste TANT que le traitement pour tes images n'est pas fait..
A moins que tu utilises une Dependency Property personnalisée qui fera le téléchargement de l'image en asynchrone puis la bindera quand ce sera bon. (Je n'en parlerai pas ici, car, ce serait assez long ). Cette dernière solution est pratique quand tu n'as pas forcément à lier ton image à un objet quelconque, mais, ce n'est pas gênant. Il y a toujours un moyen de s'en sortir.
Voici un exemple de code pour ces méthodes de lecture écriture (ce sont ces méthodes que j'ai utilisé pour pouvoir faire mon petit test).
1/ Méthode qui en prend paramètre le chemin complet de l'image + le stream qui va résulter de ton appel :
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 private void Save(string image, Stream source) { if (!_myStore.DirectoryExists(IMAGES_DIR)) { // Je vérifie si le dossier ou je vais copier mes images existe _myStore.CreateDirectory(IMAGES_DIR); } IsolatedStorageFileStream isfs = _store.CreateFile(image);//image == chemin complet vers l'image BitmapImage bitmap = new BitmapImage(); bitmap.SetSource(source); WriteableBitmap wb = new WriteableBitmap(bitmap); wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 0, 90); isfs.Close(); //TODO //tu peux incrémenter une variable qui t'indiquera le nombre d'images traitées //En comparant cette variable à ton nombre total d'item tu sauras ou pas si tu peux finalement binder ou pas ta liste }
2/ Ensuite, mes méthodes publiques (elles sont privées ici car, je faisais tout dans la même classe, le code behind de ma page MainPage.xaml).
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 //Méthode simple pour la sauvegarde en passant un lien complet + un nom d'image private void SaveImage(string imageUrl, string imageName) { BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += (bws, bwe) => { WebClient wc = new WebClient(); wc.OpenReadAsync(new Uri(imageUrl, UriKind.Absolute)); wc.OpenReadCompleted += (wcs, wce) => { if (wce.Error == null) { Save(imageName, wce.Result); } _NbProcessedImages++; }; }; bw.RunWorkerAsync(); }
Attention : Il faut savoir que le fait de sauvegarder ton image comme on le fait ne va pas la rendre forcément disponible au moment ou tu le fait (parce qu'on le fait dans un background worker pour éviter d'atténuer les performances de l'appli, et puis, parce que c'est un WebClient et que si on ne s'y prend pas comme on fait ici, ça plantera sous Mango ).
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 //Méthode simple pour la lecture //Retire le void en le remplaçant par BitmapImage. //renvoie à la fin le bi dont on a initialisé la source. //Supprime le Dispatcher + les références à this.Image :D (ça fait partie de mon test) private void ReadImage(string image) { Dispatcher.BeginInvoke(() => { BitmapImage bi = new BitmapImage(); using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { using (IsolatedStorageFileStream isfs = store.OpenFile(@image, FileMode.Open, FileAccess.Read)) { bi.SetSource(fileStream); this.Image.Height = bi.PixelHeight; this.Image.Width = bi.PixelWidth; } } this.Image.Source = bi; }); }
Bon, et ensuite ?
Alors, quand tu télécharges ton flux de données, il ne faut bien entendu pas le binder comme je te le disais. Sinon, tu n'auras pas des données correctes (pour les images), et ensuite, parce que une fois que c'est bindé, il cherchera à afficher les images.
Encore un exemple de la façon dont je m'y prends. J'ai du code spécifique à mon exemple, mais ça ne devrait pas t'empêcher de comprendre. Je mets des commentaires là ou il faut pour attirer ton attention
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 //feed est la liste finale que je vais binder à mon objet principal //Il doit être accessible de préférence partout dans ta classe //Car, il faudra vérifier dans ta méthode de sauvegarde de tes images //Si le nombre total d'item == le nombre d'images sauvegardées ShortNewsFeed feed = new ShortNewsFeed(); //C'est spécifique à mon exemple, j'utilisais du json JObject token = JObject.Parse(response.Content); var content = token["shortnewsfeed"].ToString(); var output = JsonConvert.DeserializeObject<ShortNewsFeed>(content); //Je stocke dans tmpFeed mon output, mon flux sur lequel je vais travailler ShortNewsFeed tmpFeed = output; _NbItems = tmpFeed.Items.Count; //variable privée dans ma classe contenant le nombre d'items et donc d'images à travailler _NbProcessedImages = 0; // J'initialise le nombre d'images que je vais processer à 0 //et notre fameuse boucle foreach (ShortNews item in tmpFeed.Items) { //On prépare le nouveau nom de l'image string name = string.Format("{0}{1}", Guid.NewGuid().ToString(), Path.GetExtension(item.Img)); string img = item.Img; //On modifie le path de l'image pour l'item. Il doit pointer vers l'image en local //Tu n'es pas obligé de le faire ici, et tu peux le faire juste quand tu chercheras à binder le Bitmap item.Img = Path.Combine(IMAGES_DIR, name); //On l'ajoute à notre liste finale feed.Items.Add(item); //On sauvegarde l'image ensuite SaveImage(img, name, feed); Thread.Sleep(1); }
On y arrive, c'est presque la fin. Pour pouvoir binder un BitmapImage à partir d'une url, ici dans notre cas, tu n'as qu'un seul moyen, c'est utiliser un Converter. Comme ça, à chaque fois que ton image sera binder, pour chaque item de la liste, ton url/nom d'image sera convertie en BitmapImage.
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 public class UrlToBitmapImageConverter: IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if(value == null) { return value; } string image = value.ToString(); string path = IMAGES_DIR; BitmapImage bi = new BitmapImage(); using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { if (store.FileExists(Path.Combine(path, image))) { using (IsolatedStorageFileStream fileStream = store.OpenFile(Path.Combine(path, image), FileMode.Open, FileAccess.Read)) { bi.SetSource(fileStream); } } } return bi; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion }
Et voilà, ça devrait fonctionner comme tu le souhaites :-). ça fait beaucoup d'informations en un seul post, mais, tout est dit. Si ça te va, n'oublie pas de marquer en résolu, et sinon, une fois que j'aurai écrit mon article, je mettrai à jour ce post pour le signaler.
Bonne journée !
Ma réponse vous a aidé ? Pensez à voter pour elle. N'oubliez pas non plus de changer le statut de votre thread en Résolu.
Mon blog
Ma société: So@t
Oula ! En effet je vois que tu y as mis le paquet
Je lis tout ça, l'adapte et je te dis si c'est good ou pas. Merci
Hum, pour le moment, je ne me suis occupé que du code pour sauvegarder (chaque chose en son temps). Et j'ai un comportement bizarre.
Je vérifie via un simple bouton le compteur de _NbProcessedImages, il m'indique par exemple 10. (Ce qui correspond à mes 10 items à télécharger).
Je vérifie via IsolatedStorageExplorer. Dans le dossier il n'y a qu'une image :/ Voir 2 des fois. L'explorer ne m'en affiche que 1 (ou 2) car le reste n'a pas encore était enregistré entre temps ?
Le 10 me dirait bien qu'il y a effectivement 10 images de sauvegarder.
EDIT : Après avoir essayer via affichage dans l'appli, il ne m'en sauvegarde bien qu'un certain nombre. Là 2 en l’occurrence. Et elles sont en plein milieu de la liste.
_NbProcessedImages est censé être le nombre d'images téléchargées (pas à télécharger (^_^)! Tu as moyen de vérifier que toutes les url images sont bonnes ?. Sinon, rajoute une variable pour les Images non téléchargées, et de mon côte, je reteste !
Ma réponse vous a aidé ? Pensez à voter pour elle. N'oubliez pas non plus de changer le statut de votre thread en Résolu.
Mon blog
Ma société: So@t
Oui j'avais compris que _NbprocessedImage correspondait au nombre sauvegardé (vu qu'il s'incrémente après le SaveJpeg). J'ai en tout 10 items à télécharger sur la même page.
Mes url sont bonnes je pense car elles arrivent à se charger dans la listbox déjà existante.
De plus, elles sont sur le même patron. http://www.******/dossiertruc/nomdelimage.jpg
J'ai mis un debug.writeline juste après le SaveJpeg; et il s'affiche 10 fois. Donc il passe bien 10 fois dans la fonction Save.
Alors, je ne vois pas trop d'ou ça peut venir. Je viens de refaire mes tests, et ça fonctionne bien.
IsolatedStorageExplorer a quelques soucis chez moi, donc, du coup, pour être sûr que c'est enregistré, j'ai fait ça :
Et mes images sont effectivement toutes créées (IsolatedStorageExplorer me montrait pourtant 2 images aussi).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 Debug.WriteLine("Image : {0} saved", image); if (_myStore.FileExists(image)) { Debug.WriteLine("Image has been really saved", image); } else { Debug.WriteLine("Image has NOT been really saved", image); }
Par contre, j'ai ça au début de mon MainViewModel:
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 private ShortNewsFeed _ShortNewsFeed; private ShortNewsFeed _tmpShortNewsFeed; .... public ShortNewsFeed ShortNewsFeed { get { return _ShortNewsFeed; } set { if (_ShortNewsFeed != value) { _ShortNewsFeed = value; RaisePropertyChanged("ShortNewsFeed"); } } }
Dans ma méthode ou je travaille mon flux en renommant mes images et les sauvegardant, j'ai ça :
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 foreach (ShortNews item in tmpFeed.Items) { //On prépare le nouveau nom string name = string.Format("{0}{1}", Guid.NewGuid().ToString(), Path.GetExtension(item.Img)); string img = item.Img; //On modifie le path de l'image pour l'item. Il doit pointer vers l'image en local item.Img = name; //On l'ajoute à notre liste feed.Items.Add(item); //On sauvegarde l'image SaveImage(img, name); Thread.Sleep(1); } _tmpShortNewsFeed = feed;
Je sauvegarde mon nouveau tableau (celui qui a les images avec le nouveau nom) dans un objet du même type que celui que j'ai bindé dans ma vue.
Ensuite, regarde ça :
Je vérifie que le nombre d'items que j'ai au total est égal au nombre d'items que je suis censé avoir sauvegardé. Et ce n'est qu'à ce moment là que je vais bindé mon objet temporaire à mon objet qui est lié à ma vue.
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 private int _NbProcessedImages; private void SaveImage(string imageUrl, string imageName) { BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += (bws, bwe) => { WebClient wc = new WebClient(); wc.OpenReadAsync(new Uri(imageUrl, UriKind.Absolute)); wc.OpenReadCompleted += (wcs, wce) => { _NbProcessedImages++; if (wce.Error == null) { CacheManager.Current.SaveImage(wce.Result, imageName); } if (_NbItems == _NbProcessedImages) { ShortNewsFeed = _tmpShortNewsFeed; } }; }; bw.RunWorkerAsync(); }
Et tout devrait s'afficher correctement.
Allez, un dernier test et tiens moi au courant ! POur moi, ça fonctionne!
Il ya un truc que je te recommande. Stocke que le nom de l'image pour tes items, et puis, laisse les méthodes de lecture et d'écriture gérer le chemin complet. Ce sera plus simple (au début, c'était galère pour moi aussi, je m'embrouillais rapidement).
Il est temps de clôturer ce topic, on attend plus que toi !
Ma réponse vous a aidé ? Pensez à voter pour elle. N'oubliez pas non plus de changer le statut de votre thread en Résolu.
Mon blog
Ma société: So@t
Salut !
Bon je me suis envoyé le projet vendredi soir, et j'ai pu regardé chez moi.
Alors donc ton code marchait impec ! Juste que j'avais un problème avec le nom. J'avais une variable en globale et il me reprenait le dernier nom pour toutes les images -_-
L'erreur d'abruti ^_^
Je n'ai pas encore fait la lecture, mais je ne devrait pas avoir de problème.
Je le met en résolu du coup
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager