Question

J'ai un problème étrange avec WPF, je chargeais les images du disque lors de l'exécution et de les ajouter à un conteneur de StackView. Cependant, les images ne sont pas affichées. Après un certain débogage j'ai trouvé le truc, mais ça ne fait pas vraiment de sens. Je l'ai fait une petite application de démonstration pour identifier le problème:

Créer un nouveau projet WPF et 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 usings par défaut:

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 dans le dossier bin / Debug et l'appeler 'picture.jpg'

Ce programme n'affiche rien, à moins que la ligne est commenté décommentée.

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

Les ides?

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

Était-ce utile?

La solution

Il est parce que la création a été retardée. Si vous voulez que l'image à charger immédiatement, vous pouvez simplement ajouter ce code dans la phase d'initialisation.

src.CacheOption = BitmapCacheOption.OnLoad;

comme ceci:

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

Autres conseils

Dans le code pour charger des ressources dans l'ensemble d'exécution lorsque mon image « Freq.png » était dans le dossier « Icônes » et défini comme « ressources ».

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

J'ai aussi fait fonction si quelqu'un le voudrait ...

/// <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)); 
}

Utilisation:

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

Ce comportement est étrange et bien que je ne peux pas dire pourquoi cela se produit, je peux recommander des options.

Tout d'abord, une observation. Si vous incluez l'image en tant que contenu dans VS et le copier dans le répertoire de sortie, votre code fonctionne. Si l'image est marquée comme Aucun dans VS et vous copiez sur, il ne fonctionne pas.

Solution 1: FileStream

L'objet BitmapImage accepte un UriSource ou StreamSource comme paramètre. Utilisons 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: flux reste ouvert. Si vous fermez à la fin de cette méthode, l'image ne sera pas affiché. Cela signifie que le fichier reste verrouillé en écriture sur le système.

Solution 2: MemoryStream

Ceci est essentiellement solution 1 mais vous lisez le fichier dans un flux de mémoire et passer ce flux de mémoire 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 pouvez modifier le fichier sur le système, si cela est quelque chose dont vous avez besoin.

Vous pouvez essayer de connecter les gestionnaires à divers événements de BitmapImage:

Ils pourraient vous dire un peu plus sur ce qui se passe, en ce qui concerne l'image.

Voici la méthode d'extension pour charger une image à partir 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;
}

Exemple d'utilisation:

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

simple que cela!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top