Pregunta

Tengo un problema extraño con WPF, yo estaba cargando imágenes desde el disco en tiempo de ejecución y agregarlos a un recipiente StackView. Sin embargo, no se muestran las imágenes. Después de una cierta depuración encontré el truco, pero realmente no tiene ningún sentido. He hecho una pequeña aplicación de demostración para identificar el problema:

Crear un nuevo proyecto de WPF, y pegar el código de la siguiente manera:

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, pegar a continuación usings por defecto:

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

Copiar una imagen en la carpeta bin / debug y lo llaman 'foto.jpg'

Este programa no muestra nada, a menos que la línea comentada es sin comentar.

Puede alguien explicar lo que estoy haciendo mal, o por qué sucede esto? Si se quita la imagen y ejecutar el programa genera una excepción en la línea de 'int q = ...'. Si esa línea se comenta el programa se ejecuta sin excepciones, incluso si no está presente la imagen. Carga de una imagen sólo si nessesary tiene sentido, pero entonces la imagen deben cargarse cuando agrego el control Image a la StackPanel.

Cualquier idus?

Editar:. Por cierto, si se agrega la imagen como un recurso, no es necesaria la línea 'int q = ..'

¿Fue útil?

Solución

Se debe a que la Creación se retrasó. Si desea que la imagen que se va a cargar inmediatamente, sólo tiene que añadir este código en la fase de inicio.

src.CacheOption = BitmapCacheOption.OnLoad;

como esto:

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

Otros consejos

En el código para cargar los recursos en el conjunto de la ejecución, donde mi imagen 'Freq.png' estaba en la carpeta "Iconos" y se define como "recursos".

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

También hice una función si alguien lo quisiera ...

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

Uso:

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

Este es un comportamiento extraño y aunque no puedo decir por qué esto está ocurriendo, me puede recomendar algunas opciones.

En primer lugar, una observación. Si se incluye la imagen como contenido en VS y copiarlo en el directorio de salida, el código funciona. Si la imagen se marca como Ninguno en VS y copiarlo, no funciona.

Solución 1: FileStream

El objeto BitmapImage acepta una UriSource o StreamSource como un parámetro. Vamos a usar StreamSource lugar.

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

El problema: la corriente permanece abierto. Si la cierra al final de este método, la imagen no se mostrará. Esto significa que el archivo permanece bloqueado contra escritura en el sistema.

Solución 2: MemoryStream

Esta es básicamente la solución 1, pero leer el archivo en una secuencia de memoria y pasar esa corriente de memoria como argumento.

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

Ahora usted es capaz de modificar el archivo en el sistema, si eso es algo que necesite.

Usted podría tratar de fijación manejadores para varios eventos de BitmapImage:

Se le puede decir un poco acerca de lo que está pasando, en lo que se refiere a la imagen.

Aquí está el método de extensión para cargar una imagen de 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;
}

Ejemplo de uso:

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

Tan simple como eso!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top