Pergunta

Eu tenho um problema estranho com o WPF, eu estava carregando imagens do disco em tempo de execução e adicioná-los a um contêiner StackView. No entanto, as imagens não foram exibidos. Depois de alguma depuração eu encontrei o truque, mas isso realmente não faz qualquer sentido. Eu fiz um aplicativo de demonstração pequeno para identificar o problema:

Crie um novo projeto WPF, e cole o código da seguinte forma:

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, cole abaixo usings padrão:

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 uma imagem para a pasta bin / Debug e chamá-lo 'picture.jpg'

Este programa não exibe nada, a não ser que a linha comentada é comentada.

Alguém pode explicar o que estou fazendo de errado, ou por que isso acontece? Se você remover a imagem e executar o programa gera uma exceção no 'q int = ...' linha. Se essa linha é comentado o programa é executado sem exceções, mesmo se nenhuma imagem está presente. Carregando uma imagem somente se nessesary faz sentido, mas, em seguida, a imagem deve ser carregada quando eu adicionar o controle de imagem para o StackPanel.

Qualquer ides?

Edit:. A propósito, se você adicionar a imagem como um recurso, o 'q int = ..' linha não é necessário

Foi útil?

Solução

É porque a criação foi adiada. Se você deseja que a imagem a ser carregado imediatamente, você pode simplesmente adicionar este código para a fase de inicialização.

src.CacheOption = BitmapCacheOption.OnLoad;

como este:

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

Outras dicas

No código de recurso de carga na execução de montagem, onde a minha imagem 'Freq.png' estava na pasta "Ícones" e definido como "Recursos".

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

Também fiz uma função se alguém gostaria que ...

/// <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 é um comportamento estranho e embora eu sou incapaz de dizer por que isso está ocorrendo, eu posso recomendar algumas opções.

Em primeiro lugar, uma observação. Se você incluir a imagem como conteúdo em VS e copiá-lo para o diretório de saída, o código funciona. Se a imagem é marcado como Nenhum na VS e você copiá-lo, ele não funciona.

Solução 1: FileStream

O objeto BitmapImage aceita um UriSource ou StreamSource como parâmetro. Vamos uso StreamSource vez.

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

O problema: estadias fluxo aberto. Se você fechá-lo no final deste método, a imagem não vai aparecer. Isto significa que a estadias de arquivo escrever bloqueado no sistema.

Solução 2: MemoryStream

Este é basicamente solução 1, mas você ler o arquivo em um fluxo de memória e passar esse fluxo de memória como o 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);

Agora você é capaz de modificar o arquivo no sistema, se isso é algo que você necessita.

Você poderia tentar anexar manipuladores para vários eventos de BitmapImage:

Eles podem dizer-lhe um pouco sobre o que está acontecendo, tanto quanto a imagem está em causa.

Aqui está o método de extensão para carregar uma imagem 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;
}

Amostra de uso:

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

Simples assim!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top