MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 2022
-
Modifié le 16 déc. 2017 à 13:57
Whismeril
Messages postés18417Date d'inscriptionmardi 11 mars 2003StatutContributeurDernière intervention 5 juin 2023
-
17 déc. 2017 à 10:03
Bonjour,
encore un problème dans lequel je m'englue...
Environnement :
- A gauche, un TreeView dans lequel sont affichées des noms de photos, classés par album. Le Tag du nœud contient une classe où figure le chemin de la photo.
- A droite, un PictureBox dans lequel on affiche la photo quand on clique sur une feuille du TreeView.
Copie d'écran :
Jusque là, tout va bien : je peux ajouter des photos, les afficher, les trier (depuis mon dernier post), enregistrer et restituer le total.
Le problème survient lorsque je veux supprimer une photo. J'obtiens alors une exception System.InvalidOperationException :
"Le processus ne peut pas accéder au fichier 'xxxxx', car il est en cours d'utilisation par un autre processus".
Bien sûr, avant d'utiliser la méthode File.Delete(), j'ai mis la propriété Image du PictureBox à null.
Et j'ai vérifié que le chemin était correct.
Quand la photo est affichée, elle est effectivement bien verrouillée (et c'est normal). On ne peut pas la supprimer avec l'explorateur Windows. Mais quand on en sélectionne une autre, pas moyen non plus.
En fait, toutes les photos qui ont été affichées au moins une fois ne sont plus supprimables. Il faut fermer l'application pour pouvoir effacer les fichiers avec l'explorateur Windows.
Voici le code qui affiche la photo, et celui qui voudrait l'effacer
Note : Les photos existent en deux exemplaires : une grande dans le répertoire "large", et une vignette dans le répertoire "small". La suppression échoue sur la grande photo (celle qui est affichée par défaut).
// Affichage de la photo sélectionnée
private void tvwAlbums_AfterSelect(object sender, TreeViewEventArgs e)
{
try
{
TreeNode Nd = tvwAlbums.SelectedNode; // Nœud sélectionné
TreeNode ndRoot = tvwAlbums.Nodes[0]; // Racine du TreeView
TreeNode ndAlb = Nd.Parent; // Nœud de l'album contenant la photo
if (Nd == null) return;
if (Nd.Tag == null || Nd.Tag.GetType() != typeof(alb_slide_class))
picPhoto.Image = null; // C'est pas une photo
else
{
string sSmallPath = Path.Combine(ndRoot.Name, ndAlb.Name, Global.gksSmallPath, Nd.Name);
string sLargePath = Path.Combine(ndRoot.Name, ndAlb.Name, Global.gksLargePath, Nd.Name);
if (File.Exists(sLargePath))
picPhoto.Image = Image.FromFile(sLargePath);
else if (File.Exists(sSmallPath))
picPhoto.Image = Image.FromFile(sSmallPath);
else
picPhoto.Image = null;
}
}
catch (Exception ex)
{
ErrorHandling.TraiteErreur(ex);
}
}
//-----------------------------------------------------------------
// Suppression de la photo sélectionnée
private void mnuPhotoDelete_Click(object sender, EventArgs e)
{
try
{
TreeNode Nd = tvwAlbums.SelectedNode;
if (Nd == null)
{
MessageBox.Show("Veuillez sélectionner la photo à supprimer.");
return;
}
alb_slide_class Slide = Nd.Tag as alb_slide_class;
if (Slide == null) // C'est pas une photo (Tag pas du bon type)
{
MessageBox.Show("Veuillez sélectionner une photo.");
return;
}
// Demande de confirmation
string sSlide = Slide.title != "" ? Slide.title : Slide.path;
if (MessageBox.Show("Vous allez supprimer la photo \"" + sSlide + "\".\n\nVous confirmez ?", "Suppression photo", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation)
== DialogResult.Cancel)
return;
// La photo est sélectionnée et donc son image est affichée.
// Le fichier est donc verrouillé.
// il faut effacer l'image pour pouvoir supprimer le fichier
picPhoto.Image = null;
tvwAlbums.SelectedNode = Nd.Parent;
tvwAlbums_AfterSelect(null, null);
Application.DoEvents();
picPhoto.Refresh();
// Ça ne marche pas !!!
album_class album = Nd.Parent.Tag as album_class;
string sSlidePath;
sSlidePath = Path.Combine(mConf.config.LocalPath, album.common.path, "large", Slide.path);
File.Delete(sSlidePath); // Suppression de la grande image
sSlidePath = Path.Combine(mConf.config.LocalPath, album.common.path, "small", Slide.path);
File.Delete(sSlidePath); // Suppression de la vignette
album.slides.Remove(Slide);
album.Modified = true;
tvwAlbums.Nodes.Remove(Nd);
}
catch (Exception ex)
{
ErrorHandling.TraiteErreur(ex);
}
}
Quelqu'un saurait me dire comment détacher la main-mise de l'application sur le fichier ?
MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 20222 16 déc. 2017 à 18:28
J'avais déjà essayé, sans succès :
picPhoto.Image.Dispose();
picPhoto.Image = null;
Le fichier est toujours verrouillé et j'ai l'exception sur le File.Delete()
Ce n'est donc pas la solution.
Il faudrait peut-être supprimer carrément le PictureBox, mais cela m'ennuie car il faudrait recréer à chaque fois ses propriétés, qui sont assez différentes de celles par défaut.
D'ailleurs j'ai même essayé
picPhoto = new PictureBox();
et j'ai toujours l'exception Fichier verrouillé.
La documentation de Image.FromFile() dit :
Page française : "Le fichier reste verrouillé jusqu'à ce que le Image est supprimé."
Page anglaise : "The file remains locked until the Image is disposed."
Il me semble qu'après Dispose() et =null, ce devrait être le cas. Il s'avère que non.
NHenry
Messages postés15069Date d'inscriptionvendredi 14 mars 2003StatutModérateurDernière intervention29 mai 2023158 Modifié le 16 déc. 2017 à 19:00
De base, je préfère stocker en local pour supprimer :
Il est aussi possible que le PictureBox sauvegarde certaines données (donc in .Dispose pour la PictureBox).
Pour régen les propriétés, tu peux regarder dans le fichier .Designer de ta form pour avoir un code tout prêt de màj des propriétés.
MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 20222 Modifié le 16 déc. 2017 à 19:40
Je crois que j'ai trouvé une solution.
Lors de la suppression d'un album entier, j'avais le même problème pour supprimer les répertoires "large" et "small". Après beaucoup d'essais, j'avais fini par forcer le répertoire courant avec SetCurrentDirectory() dans un autre répertoire (celui de l'application, qui existe forcément). Le problème avait disparu.
Je viens de faire la même chose avant la suppression d'une photo, et à priori je n'ai plus de problème.
J'ai du mal à comprendre pourquoi le fait de charger une photo verrouille l'ensemble du répertoire.
Mais je dis souvent que l'informatique n'est pas une science exacte. C'est particulièrement vrai avec Windows...
Quelques minutes plus tard... Je crois que j'ai chanté victoire un peu vite.
Certaines photos ne posent pas de problème, d'autres créent systématiquement l'erreur, sans que j'arrive à déterminer la différence.
Quand une photo coince, j'arrive à la supprimer parfois en changeant d'album (donc de répertoire) et en affichant une de ses photo, puis en revenant sur la photo qui coince, qui alors accepte d'être supprimée.
Pourtant, dans la routine de suppression, on fait déjà un changement de répertoire, comme dit ci-dessus :
Encore quelques minutes plus tard... J'ai pris le mors aux dents, et j'ai carrément chargé dans le PictureBox une photo hors de tout album avant la suppression du fichier courant.
Après avoir supprimé une cinquantaine de photos dans différents albums, je n'ai plus eu le problème que sur une photo ou deux. Et en changeant d'album puis en revenant sur la photo, ça passe.
Il va falloir que je mettre un grand texte explicatif sur le message d'erreur pour expliquer ce qui se passe et comment faire...
C'est pas très top pour une application qui est censée être de niveau professionnel et diffusée sur le web.
D'autant que les versions précédentes, développées en VB6 depuis près de 10 ans, n'avaient aucun problème.
J'ai l'impression de faire du Microsoft : chaque version est pire que la précédente... (98 => 2000/Millenium, XP => Vista, Win7 => Win8, Win10 => je crains le pire)
MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 20222 16 déc. 2017 à 20:12
Suite (et fin j'espère) du feuilleton
J'ai placé le code suivant dans la routine d'affichage de la photo (tvwAlbums_AfterSelect - voir le début du topic) AVANT le chargement de la photo en cours :
Depuis, plus de problème (enfin, jusqu'à présent).
En fait, le problème semblait se produire lorsque je revenais plusieurs fois sur la photo avant de la supprimer. D'où l'idée qu'elle était plusieurs fois en mémoire.
J'en ai déduit que FromFile remplace l'image, mais ne supprime pas la précédente (j'ai pourtant attendu longtemps que le GC fasse son boulot, mais rien à faire).
En déchargeant explicitement l'image avant de charger la suivante, il semblerait que le problème soit résolu.
Mais je vais encore attendre un peu avant de marquer ce sujet comme résolu.
Whismeril
Messages postés18417Date d'inscriptionmardi 11 mars 2003StatutContributeurDernière intervention 5 juin 2023624 16 déc. 2017 à 21:04
Bonsoir, plus simplement peut-être,
regarder quelle photo est chargée et ne pas la recharger une nouvelle fois (en stockant le chemin par exemple).
Tu gagnerais en temps d'exécution, en accès disque, etc...
MGD Software
Messages postés193Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 20222 17 déc. 2017 à 09:49
Mais justement, je ne veux pas qu'il y ait une photo chargée afin de pouvoir supprimer n'importe laquelle. Il n'y a en permanence qu'une seule photo affichée à la fois, et encore pas toujours : si on clique sur un nœud d'album, il n'y a pas de photo affichée. Le problème que je rencontre n'est pas le chargement, mais le déchargement. Le temps de chargement est dérisoire par rapport à l'action de l'utilisateur, et le but de l'application n'est pas de présenter un diaporama mais de le préparer pour un envoi sur Internet.
Je pense que la gestion de la mémoire des photos chargées est beaucoup plus complexe que décharger la dernière à chaque fois, et de toute façon ne résout pas le problème du déchargement. Si je n'ai plus d'erreur de verrouillage, je vais rester comme ça.
Whismeril
Messages postés18417Date d'inscriptionmardi 11 mars 2003StatutContributeurDernière intervention 5 juin 2023624 17 déc. 2017 à 10:03