69 votes

Image UriSource et liaison de données

J'essaie de lier une liste d'objets personnalisés à une image WPF comme ceci :

<Image>
    <Image.Source>
        <BitmapImage UriSource="{Binding Path=ImagePath}" />
    </Image.Source>
</Image>

Mais cela ne fonctionne pas. Voici l'erreur que je reçois :

"La propriété 'UriSource' ou la propriété 'StreamSource' doit être définie."

Qu'est-ce que je rate ?

1 votes

Malheureusement, la raison réelle de cet échec n'est pas expliquée dans les réponses. Voir ce ( Pour une raison quelconque, WPF/XAML ne prend pas en charge la liaison directe d'un objet Uri à l'UriSource d'un objet BitmapImage. Lors de l'exécution, l'application échoue avec une erreur, )

85voto

Brian Leahy Points 7840

WPF dispose de convertisseurs intégrés pour certains types. Si vous liez l'élément Source à une propriété string ou Uri sous le capot, WPF utilisera une valeur de type ImageSourceConverter pour convertir la valeur en un ImageSource .

Alors

<Image Source="{Binding ImageSource}"/>

fonctionnerait si la propriété ImageSource était une représentation en chaîne d'une URI valide vers une image.

Vous pouvez bien sûr créer votre propre convertisseur Binding :

public class ImageConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        return new BitmapImage(new Uri(value.ToString()));
    }

    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

et l'utiliser comme ceci :

<Image Source="{Binding ImageSource, Converter={StaticResource ImageConverter}}"/>

4 votes

(En fait, le convertisseur de type ne crée pas de fichier BitmapImage mais une autre sous-classe de ImageSource : BitmapFrameDecode qui est interne).

0 votes

@H.B. Comment vous reconvertissez-vous si vous voulez persister dans le changement de l'image ?

0 votes

Alternative à un convertisseur : Faites votre propriété que vous liez à (ici : ImageSource ) de type Uri ou BitmapImage et lancez là. Si vous devez faire face à de possibles null valeurs (cast failed etc.) ajouter TargetNullValue={x:Null} à votre fixation.

21voto

Drew Noakes Points 69288

Cet article d'Atul Gupta contient un exemple de code qui couvre plusieurs scénarios :

  1. Lier une image de ressource régulière à la propriété Source dans XAML
  2. Image de ressource de liaison, mais à partir du code derrière
  3. Lier l'image de ressource dans le code derrière en utilisant Application.GetResourceStream
  4. Chargement d'une image à partir d'un chemin de fichier via un flux de mémoire (il en va de même pour le chargement d'images de blog à partir d'une base de données).
  5. Chargement d'une image à partir d'un chemin de fichier, mais en utilisant la liaison à un chemin de fichier Propriété
  6. Lier des données d'image à un contrôle utilisateur qui possède en interne un contrôle d'image via la propriété de dépendance.
  7. Comme au point 5, mais en s'assurant que le fichier n'est pas verrouillé sur le disque dur.

18voto

palehorse Points 8268

Vous pouvez aussi simplement définir l'attribut Source plutôt que d'utiliser les éléments enfants. Pour ce faire, votre classe doit renvoyer l'image sous forme d'image bitmap. Voici un exemple de la façon dont je l'ai fait

<Image Width="90" Height="90" 
       Source="{Binding Path=ImageSource}"
       Margin="0,0,0,5" />

Et la propriété de la classe est simplement ceci

public object ImageSource {
    get {
        BitmapImage image = new BitmapImage();

        try {
            image.BeginInit();
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
            image.UriSource = new Uri( FullPath, UriKind.Absolute );
            image.EndInit();
        }
        catch{
            return DependencyProperty.UnsetValue;
        }

        return image;
    }
}

Je suppose que cela représente un peu plus de travail que le convertisseur de valeur, mais c'est une autre option.

1 votes

Une implémentation similaire à celle-ci est parfaite lorsque votre ressource bitmap est déjà chargée dans votre objet et que vous voulez passer les bits à la liaison. MERCI !

8voto

Dale Ragan Points 14495

Vous devez disposer d'une implémentation de IValueConverter qui convertit l'uri en une image. Votre implémentation Convert de IValueConverter ressemblera à quelque chose comme ceci :

BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(value as string);
image.EndInit();

return image;

Vous devrez alors utiliser le convertisseur dans votre fixation :

<Image>
    <Image.Source>
        <BitmapImage UriSource="{Binding Path=ImagePath, Converter=...}" />
    </Image.Source>
</Image>

0 votes

Il semble que le convertisseur renvoie un BitmapImage et le résultat doit être affecté à Image.Source directement, pas à un autre BitmapImage UriSource .

8voto

Luis Cantero Points 121

Le problème avec la réponse choisie ici est que lors de la navigation en avant et en arrière, le convertisseur sera déclenché à chaque fois que la page sera affichée.

De nouveaux gestionnaires de fichiers sont ainsi créés en permanence et bloquent toute tentative de suppression du fichier, car il est toujours utilisé. Ceci peut être vérifié en utilisant l'Explorateur de processus.

Si le fichier image risque d'être supprimé à un moment donné, un convertisseur tel que celui-ci peut être utilisé : Utilisation de XAML pour lier une image System.Drawing.Image à un contrôle System.Windows.Image.

L'inconvénient de cette méthode de flux de mémoire est que la ou les images sont chargées et décodées à chaque fois et qu'aucune mise en cache ne peut avoir lieu : "Pour éviter que les images soient décodées plus d'une fois, assignez la propriété Image.Source à partir d'un Uri plutôt que d'utiliser les flux de mémoire" Source : "Conseils de performance pour les applications Windows Store utilisant XAML"

Pour résoudre le problème de performance, le modèle de référentiel peut être utilisé pour fournir une couche de mise en cache. La mise en cache peut se faire en mémoire, ce qui peut entraîner des problèmes de mémoire, ou sous forme de fichiers de vignettes résidant dans un dossier temporaire qui peut être effacé lorsque l'application se termine.

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