49 votes

Chargement dynamique des images dans WPF

J'ai un étrange problème avec WPF, j'était en train de charger des images à partir du disque lors de l'exécution et de les ajouter à une Empilervoir conteneur. Cependant, les images ne sont pas affichées. Après un peu de débogage, j'ai trouvé le truc, mais ça n'a pas vraiment de sens. J'ai fait une petite démo app pour identifier le problème:

Créer un nouveau projet WPF, et de coller le code comme suit:

xaml:

<Window x:Class="wpfBug.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
    <StackPanel Name="sp">
    </StackPanel>
</Window>

xaml.cs, coller ci-dessous par défaut de l'usage:

namespace wpfBug
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Image i = new Image();
            BitmapImage src = new BitmapImage();
            src.BeginInit();
            src.UriSource = new Uri("picture.jpg", UriKind.Relative);
            src.EndInit();
            i.Source = src;
            i.Stretch = Stretch.Uniform;
            //int q = src.PixelHeight;        // Image loads here
            sp.Children.Add(i);
        }
    }
}

Copier une image pour la bin/Debug dossier et de l'appeler 'picture.jpg'

Ce programme n'a pas d'afficher quoi que ce soit, à moins que la ligne de commentaire est sans commentaire.

Quelqu'un peut-il expliquer ce que je fais mal, ou pourquoi cela se produit? Si vous supprimez l'image et exécuter le programme il génère une exception sur le 'int q= ...' ligne. Si cette ligne est commentée le programme s'exécute sans exceptions, même si aucune image n'est présente. Chargement d'une image uniquement si nessesary de sens, mais l'image doit être chargée lorsque j'ajoute le contrôle de l'Image de la StackPanel.

Toute ide ?

Edit: En passant, si vous ajoutez l'image en tant que ressource, l' 'int q = ..' ligne n'est pas nécessaire.

101voto

redjackwong Points 931

C'est parce que la création a été retardée. Si vous souhaitez que l'image soit chargée immédiatement, vous pouvez simplement ajouter ce code dans la phase d'initialisation.

src.CacheOption = BitmapCacheOption.OnLoad;

comme ça:

 src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
 

11voto

Eric Ouellet Points 1370

Dans le code pour charger la ressource dans l'assembly en cours d'exécution, où mon image 'Freq.png' était dans le dossier "Icons" et définie comme "Resource".

         this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/" 
             + Assembly.GetExecutingAssembly().GetName().Name 
             + ";component/" 
             + "Icons/Freq.png", UriKind.Absolute)); 
 

J'ai aussi créé une fonction si quelqu'un le souhaitait ...

 /// <summary>
/// Load a resource WPF-BitmapImage (png, bmp, ...) from embedded resource defined as 'Resource' not as 'Embedded resource'.
/// </summary>
/// <param name="pathInApplication">Path without starting slash</param>
/// <param name="assembly">Usually 'Assembly.GetExecutingAssembly()'. If not mentionned, I will use the calling assembly</param>
/// <returns></returns>
public static BitmapImage LoadBitmapFromResource(string pathInApplication, Assembly assembly = null)
{
    if (assembly == null)
    {
        assembly = Assembly.GetCallingAssembly();
    }

    if (pathInApplication[0] == '/')
    {
        pathInApplication = pathInApplication.Substring(1);
    }
    return new BitmapImage(new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component/" + pathInApplication, UriKind.Absolute)); 
}
 

Usage:

         this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png");
 

7voto

Szymon Rozga Points 11277

C'est un comportement étrange et bien que je suis incapable de dire pourquoi cela se produit, je peux vous recommander quelques options.

Tout d'abord, une observation. Si vous inclure l'image dans le Contenu de VS et de le copier dans le répertoire de sortie, votre code fonctionne. Si l'image est marqué comme Aucun de VS et vous la copier, il ne fonctionne pas.

Solution 1: FileStream

L'objet BitmapImage accepte un UriSource ou StreamSource en tant que paramètre. Nous allons utiliser StreamSource à la place.

        FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read);
        Image i = new Image();
        BitmapImage src = new BitmapImage();
        src.BeginInit();
        src.StreamSource = stream;
        src.EndInit();
        i.Source = src;
        i.Stretch = Stretch.Uniform;
        panel.Children.Add(i);

Le problème: le flux reste ouverte. Si vous la fermer à la fin de cette méthode, l'image ne s'affichera pas. Cela signifie que le fichier reste en écriture verrouillé sur le système.

Solution 2: MemoryStream

C'est essentiellement la solution 1, mais vous lire le fichier dans un flux de mémoire et de transmettre cette mémoire de flux comme argument.

        MemoryStream ms = new MemoryStream();
        FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read);
        ms.SetLength(stream.Length);
        stream.Read(ms.GetBuffer(), 0, (int)stream.Length);

        ms.Flush();
        stream.Close();

        Image i = new Image();
        BitmapImage src = new BitmapImage();
        src.BeginInit();
        src.StreamSource = ms;
        src.EndInit();
        i.Source = src;
        i.Stretch = Stretch.Uniform;
        panel.Children.Add(i);

Maintenant, vous êtes en mesure de modifier le fichier sur le système, si c'est quelque chose dont vous avez besoin.

2voto

Drew Noakes Points 69288

Vous pouvez essayer de fixer des gestionnaires d'événements divers de BitmapImage:

Ils peuvent vous dire un peu ce qui se passe, d'autant que l'image est concerné.

0voto

J Pollack Points 1067

Voici la méthode d'extension pour charger une image à partir de l'URI:

 public static BitmapImage GetBitmapImage(
    this Uri imageAbsolutePath,
    BitmapCacheOption bitmapCacheOption = BitmapCacheOption.Default)
{
    BitmapImage image = new BitmapImage();
    image.BeginInit();
    image.CacheOption = bitmapCacheOption;
    image.UriSource = imageAbsolutePath;
    image.EndInit();

    return image;
}
 

Échantillon d'utilisation:

 Uri _imageUri = new Uri(imageAbsolutePath);
ImageXamlElement.Source = _imageUri.GetBitmapImage(BitmapCacheOption.OnLoad);
 

Aussi simple que cela!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X