2010-04-04 16 views
8

que tienen debajo de código XAML:Enlace Image.Source to String en WPF?

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    DataContext="{Binding RelativeSource={RelativeSource Self}}" 
    WindowStartupLocation="CenterScreen" 
    Title="Window1" Height="300" Width="300"> 

    <Grid> 
     <Image x:Name="TestImage" Source="{Binding Path=ImageSource}" /> 
    </Grid> 

</Window> 

Además, hay un método que hace una imagen de una cadena Base64:

Image Base64StringToImage(string base64ImageString) 
{ 
    try 
    { 
     byte[] b; 
     b = Convert.FromBase64String(base64ImageString); 
     MemoryStream ms = new System.IO.MemoryStream(b); 
     System.Drawing.Image img = System.Drawing.Image.FromStream(ms); 

     ////////////////////////////////////////////// 
     //convert System.Drawing.Image to WPF image 
     System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(img); 
     IntPtr hBitmap = bmp.GetHbitmap(); 
     System.Windows.Media.ImageSource imageSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 

     Image wpfImage = new Image(); 
     wpfImage.Source = imageSource; 
     wpfImage.Width = wpfImage.Height = 16; 
     ////////////////////////////////////////////// 

     return wpfImage; 
    } 
    catch 
    { 
     Image img1 = new Image(); 
     img1.Source = new BitmapImage(new Uri(@"/passwordManager;component/images/TreeView/empty-bookmark.png", UriKind.Relative)); 
     img1.Width = img1.Height = 16; 
     return img1; 
    } 
} 

Ahora, voy a TestImage se unen a la salida del Base64StringToImage método.
he utilizado de la siguiente manera:

public string ImageSource { get; set; } 
ImageSource = Base64StringToImage("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABjUExURXK45////6fT8PX6/bTZ8onE643F7Pf7/pDH7PP5/dns+b7e9MPh9Xq86NHo947G7Hm76NTp+PL4/bHY8ojD67rc85bK7b3e9MTh9dLo97vd8/D3/Hy96Xe76Nfr+H+/6f///1bvXooAAAAhdFJOU///////////////////////////////////////////AJ/B0CEAAACHSURBVHjaXI/ZFoMgEEMzLCqg1q37Yv//KxvAlh7zMuQeyAS8d8I2z8PT/AMDShWQfCYJHL0FmlcXSQTGi7NNLSMwR2BQaXE1IfAguPFx5UQmeqwEHSfviz7w0BIMyU86khBDZ8DLfWHOGPJahe66MKe/fIupXKst1VXxW/VgT/3utz99BBgA4P0So6hyl+QAAAAASUVORK5CYIII").Source.ToString(); 

pero nada sucede.
¿Cómo puedo solucionarlo?

Por cierto, estoy completamente seguro de que la cadena de base 64 es correcta

+0

No es relevante para su pregunta, pero ¿ha intentado cargar la imagen con 'var img = new BitmapImage {StreamSource = ms} '? –

+0

@Simon: NO, no lo hice. pero, ¿por qué he hecho eso? –

+3

Bueno, puede cargar la imagen directamente con WPF, en lugar de a través de GDI + (System.Drawing). Como está destinado a ser utilizado desde XAML, en realidad tiene que hacer 'var source = new BitmapImage(); source.BeginInit(); source.StreamSource = ms; source.EndInit() '. –

Respuesta

14

Como complemento a la excelente respuesta de @ itowlson, esto es lo que el código debe ser similar:

// MainWindow.xaml 
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <DockPanel> 
     <Image Source="{Binding ImageSource}" /> 
    </DockPanel> 
</Window> 

// MainWindow.xaml.cs 
using System.ComponentModel; 
using System.IO; 
using System.Windows; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     var model = new MainModel(); 
     DataContext = model; 

     model.SetImageData(File.ReadAllBytes(@"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg")); 
    } 
} 

class MainModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public void SetImageData(byte[] data) { 
     var source = new BitmapImage(); 
     source.BeginInit(); 
     source.StreamSource = new MemoryStream(data); 
     source.EndInit(); 

     // use public setter 
     ImageSource = source; 
    } 

    ImageSource imageSource; 
    public ImageSource ImageSource 
    { 
     get { return imageSource; } 
     set 
     { 
      imageSource = value; 
      OnPropertyChanged("ImageSource"); 
     } 
    } 

    protected void OnPropertyChanged(string name) 
    { 
     var handler = PropertyChanged; 
     if (null != handler) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
} 
+0

Gracias, lo he hecho, pero no se ha mostrado nada. Solo se mostró una cadena en lugar de image => 'WpfApplication1.MainModel'. puedes descargar mi proyecto de http://www.mediafire.com/?nze3qjmzjtm –

+0

Casi, es 'DataContext = model;', no 'Content = model;'. Además, puede usar 'Convert.FromBase64String (...)' directamente en 'SetImageData()', 'BitmapImage' puede cargar las mismas imágenes que' System.Drawing.Image'. –

+0

Muchas gracias, hermano, realmente lo necesitaba. Gracias :-) –

22

Vamos a romper lo que está haciendo.

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

Para que esto funcione, el origen de enlace tiene que ser o bien una ImageSource, o una cadena que representa un URI a un archivo de imagen. Así que echemos un vistazo a lo que realmente es la propiedad de ImageSource.

public string ImageSource { get; set; } 

Un problema aquí es que ImageSource no está provocando eventos PropertyChanged. Entonces, WPF no actualizará el destino vinculante cuando actualice la propiedad.

Pero también, ImageSource no es una ImageSource, es una cadena. Está bien, pero WPF interpretará esa cadena como un URI. ¿Qué es ese URI?

ImageSource = Base64StringToImage(BIG_HONKING_STRING).Source.ToString(); 

Este es el meollo de su problema. La cadena de ImageSource no es realmente un URI, porque su imagen no es un recurso direccionable. Base64StringToImage crea un ImageSource en memoria desde la cadena base64, luego regresa una Imagen con esa fuente. Luego tomas la fuente de la imagen (que es un objeto ImageSource) y la escribes. Eso podría funcionar si ImageSource proviene de un archivo o URL, pero no fue así: proviene de un HBITMAP. Entonces, el resultado de ToString() no tendrá sentido. Así que ImageSource se está configurando como algo sin sentido, y su Imagen está tratando de interpretar esta cosa sin sentido como la URL de un archivo de mapa de bits.

Así que para solucionar este problema, hay que hacer tres cosas:

  1. provocar el evento PropertyChanged para la propiedad ImageSource (o hacer que sea una propiedad de dependencia).
  2. Cambie la propiedad ImageSource para que sea del tipo ImageSource en lugar de escribir una cadena (para que pueda contener fuentes de imagen sin URL).
  3. Cambie su llamada setter para configurar ImageSource en Base64StringToImage(...).Source - es decir, eliminar la llamada ToString(). Mejor aún, cambie Base64StringToImage para devolver un ImageSource en lugar de una imagen: la creación de un elemento de imagen solo crea sobrecarga porque todo lo que realmente le interesa es BitmapSource.
+0

'Image.Source' también se puede vincular a un' Stream' o 'byte []' – Schneider