2008-08-21 15 views
57

Ich versuche, eine Liste der benutzerdefinierten Objekte zu einem WPF-Bild wie folgt zu binden:Bild UriSource und Datenbindung

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

Aber es funktioniert nicht. Dies ist der Fehler, den ich erhalte:

"Eigenschaft 'UriSource' oder Eigenschaft 'StreamSource' muss gesetzt sein."

Was fehlt mir?

Antwort

74

WPF hat für bestimmte Typen eingebaute Konverter. Wenn Sie die Source Eigenschaft des Bilds an einen Wert string oder Uri binden, wird WPF unter der Haube einen ImageSourceConverter verwenden, um den Wert in ImageSource zu konvertieren.

So

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

funktionieren würde, wenn die Image Eigenschaft eine String-Darstellung eines gültigen URI zu einem Bild ist.

Sie können Ihre eigenen Binding-Wandler natürlich rollen:

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

und es wie folgt verwendet werden:

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

(Tatsächlich erzeugt der Typkonverter kein 'BitmapImage', sondern eine andere Unterklasse von' ImageSource': 'BitmapFrameDecode', was intern ist.) –

+0

@ H.B. Wie würden Sie zurück konvertieren, wenn Sie die Änderung des Bildes beibehalten möchten? – Igor

+0

Alternative zu einem Konverter: Machen Sie Ihre Eigenschaft, an die Sie binden (hier: 'ImageSource') vom Typ' Uri' oder 'BitmapImage', und geben Sie sie dort ein. Wenn Sie mit möglichen 'Null'-Werten umgehen müssen (Cast fehlgeschlagen usw.), fügen Sie 'TargetNullValue = {x: Null}' zu Ihrer Bindung hinzu. – Gerrit

9

Sie müssen eine Implementierung von IValueConverter Schnittstelle haben, die die URI in ein Bild konvertiert. Ihre Convert Implementierung von IValueConverter wird wie folgt aussehen:

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

return image; 

Dann müssen Sie den Konverter verwenden, in Ihrer Bindung:

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

Sie können auch einfach die Quelle Attribut eher eingestellt als das Kind mit Elemente. Um dies zu tun, muss Ihre Klasse das Bild als Bitmap-Bild zurückgeben. Hier ist ein Beispiel für eine Art, wie ich es

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

und die Klasse Eigenschaft ist einfach diese

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

ich es annehmen getan haben vielleicht ein wenig mehr Arbeit als der Wert Konverter sein, aber es ist andere Option.

+1

Eine ähnliche Umsetzung dieses wollen, ist perfekt, wenn Sie Ihre Bitmap-Ressource bereits in Ihrem Objekt geladen wird und Sie möchten die Bits an die Bindung übergeben. VIELEN DANK! –

23

This article von Atul Gupta hat Beispielcode, der mehrere Szenarien umfasst:

  1. Reguläre Ressourcenbildbindung an Source-Eigenschaft in XAML
  2. Binding Ressource Bild, aber aus dem Code hinter
  3. Binding Ressourcenbild im Code hinter Anwendung.GetResourceStream
  4. Lade Bild von Dateipfad über Speicherstrom (gleiches gilt, wenn Blog-Bilddaten aus der Datenbank geladen)
  5. Lade Bild von Dateipfad, sondern von Eigentum auf einen Dateipfad Bindung mit
  6. Binding Bilddaten einem Benutzersteuerung, die intern Bildsteuerung über Abhängigkeitseigenschaft
  7. die gleiche wie Punkt 5 auf, sondern auch sicherzustellen, dass die Datei nicht auf der Festplatte gesperrt bekommt
6

das Problem mit der Antwort, die hier gewählt wurde, ist, dass Beim Navigieren hin und her wird der Konverter kommen wird jedes Mal ausgelöst, wenn die Seite angezeigt wird.

Dies führt dazu, dass neue Datei-Handles kontinuierlich erstellt werden und jeden Versuch blockieren, die Datei zu löschen, da sie noch verwendet wird. Dies kann mit dem Process Explorer überprüft werden.

Wenn die Bilddatei kann zu einem bestimmten Zeitpunkt gelöscht werden, ein Konverter wie diese verwendet werden könnten: using XAML to bind to a System.Drawing.Image into a System.Windows.Image control

Der Nachteil bei dieser Methode Speicherstrom ist, dass das Bild (n) geladen werden und decodiert jedes Mal, und kein Caching stattfinden kann: „Um Bilder zu verhindern, dass mehr als einmal decodiert wird, weisen die Image.Source Eigenschaft von einem Uri anstatt Speicher mit Hilfe von Streams“ Quelle: „Performance-Tipps für Windows-Store-Anwendungen mithilfe von XAML“

Um das Leistungsproblem zu lösen, kann das Repository-Muster verwendet werden, um eine Cache-Schicht bereitzustellen. Das Zwischenspeichern kann im Speicher stattfinden, was zu Speicherproblemen führen kann, oder als Thumbnail-Dateien, die sich in einem temporären Ordner befinden, der beim Beenden der App gelöscht werden kann.

4

können Sie

verwenden

ImageSourceConverter Klasse

zu bekommen, was Sie

img1.Source = (ImageSource)new ImageSourceConverter().ConvertFromString("/Assets/check.png");