Динамическая загрузка изображений в WPF - PullRequest
48 голосов
/ 20 февраля 2009

У меня странная проблема с WPF, я загружал изображения с диска во время выполнения и добавлял их в контейнер StackView. Однако изображения не отображались. После некоторой отладки я нашел хитрость, но это действительно не имеет никакого смысла. Я сделал небольшое демонстрационное приложение, чтобы определить проблему:

Создайте новый проект WPF и вставьте код следующим образом:

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, вставьте ниже значений по умолчанию:

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

Скопируйте изображение в папку bin / Debug и назовите его «picture.jpg»

Эта программа ничего не отображает, если закомментированная строка не закомментирована.

Может кто-нибудь объяснить, что я делаю неправильно, или почему это происходит? Если вы удалите изображение и запустите программу, она сгенерирует исключение в строке 'int q = ...'. Если эта строка закомментирована, программа запускается без исключений, даже если изображение отсутствует. Загрузка изображения только в том случае, если это имеет смысл, но тогда изображение должно быть загружено, когда я добавляю элемент управления Image в StackPanel.

Любые иды?

Редактировать: Кстати, если вы добавляете изображение в качестве ресурса, строка 'int q = ..' не нужна.

Ответы [ 5 ]

97 голосов
/ 24 февраля 2009

Это потому, что Сотворение было отложено. Если вы хотите, чтобы изображение загружалось немедленно, вы можете просто добавить этот код в фазу инициализации.

src.CacheOption = BitmapCacheOption.OnLoad;

как это:

src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
11 голосов
/ 16 марта 2012

В коде для загрузки ресурса в исполняющую сборку, где мое изображение 'Freq.png' находилось в папке «Значки» и определено как «Ресурс».

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

Я также сделал функцию, если кому-то захочется ...

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

Использование:

        this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png");
7 голосов
/ 20 февраля 2009

Это странное поведение, и хотя я не могу сказать, почему это происходит, я могу порекомендовать некоторые варианты.

Во-первых, наблюдение. Если вы включаете изображение как Контент в VS и копируете его в выходной каталог, ваш код работает. Если изображение помечено как None в VS, и вы копируете его, оно не работает.

Решение 1: FileStream

Объект BitmapImage принимает UriSource или StreamSource в качестве параметра. Давайте вместо этого воспользуемся StreamSource.

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

Проблема: поток остается открытым. Если вы закроете его в конце этого метода, изображение не будет отображаться. Это означает, что файл остается заблокированным для записи в системе.

Решение 2: MemoryStream

Это в основном решение 1, но вы читаете файл в поток памяти и передаете этот поток памяти в качестве аргумента.

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

Теперь вы можете изменить файл в системе, если это то, что вам нужно.

0 голосов
/ 16 апреля 2013

Вот метод расширения для загрузки изображения из 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;
}

Образец использования:

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

Все просто!

0 голосов
/ 20 февраля 2009

Вы можете попробовать подключить обработчики к различным событиям BitmapImage:

Они могут немного рассказать вам о том, что происходит, в отношении изображения.

...