Ресурсы изображений WPF

409

Я пришел в основном из Интернета и немного из Windows Forms. Для нового проекта мы будем использовать WPF. Приложению WPF понадобится от 10 до 20 маленьких иконок и изображений для иллюстративных целей. Я думаю о том, чтобы хранить их в сборке как встроенные ресурсы. Это правильный путь?

Как указать в XAML, что элемент управления Image должен загружать изображение из встроенного ресурса?

driis
источник

Ответы:

473

Если вы будете использовать изображение в нескольких местах, то стоит загрузить данные изображения только один раз в память и затем разделить их между всеми Imageэлементами.

Для этого создайте BitmapSource в качестве ресурса где-нибудь:

<BitmapImage x:Key="MyImageSource" UriSource="../Media/Image.png" />

Затем в вашем коде используйте что-то вроде:

<Image Source="{StaticResource MyImageSource}" />

В моем случае я обнаружил, что для Image.pngфайла нужно настроить действие сборки, Resourceа не просто Content. Это заставляет изображение переноситься в вашей скомпилированной сборке.

Дрю Ноакс
источник
6
Было бы возможно сделать это динамически? Если у меня разное количество изображений, которые я хотел бы загрузить при запуске, могу ли я создать BitmapSource для каждого изображения и ссылаться на них так же, как указано выше?
Бекки Франклин
2
@Becky - Да, вы можете, хотя, если вы хотите сослаться на них в Xaml, вам, возможно, придется использовать DynamicResourceрасширение разметки вместо того StaticResource, чтобы предполагать, что вы будете знать ключи во время компиляции. В WPF вы можете создавать словари ресурсов во время выполнения. Фактически, это то, что происходит, когда вы загружаете документ Xaml, просто вы не видите эквивалентный C #.
Дрю Ноакс
9
Что-то, что я ударил: если вы добавляете свой ресурс изображений в словарь ресурсов, не забудьте сослаться на этот словарь изображений в XAML для вашего компонента. Примерно так: <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source = "Dictionary1.xaml" /> </ResourceDictionary.MergedDictionaries> </ ResourceDictionary> </UserControl.Resources>
Дэн Митчелл
4
Я обычно добавляю Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" к ним Image, так как в противном случае я часто вижу, что изображения по каким-то причинам увеличиваются в гротескном масштабе (например, значки 16x16 растягиваются до размера, который выглядит как 200x200 пикселей).
ИЛИ Mapper
5
Я обнаружил, что если BitmapImage объявлен в ресурсном слове ссылочной сборки, UriSource должен быть packURI, чтобы это работало. В противном случае вы обнаружите, что вы можете видеть изображение в редакторе xaml в VS, но при отладке изображение отсутствует. Пакет URIS: msdn.microsoft.com/en-au/library/aa970069(v=vs.100).aspx
неудачное программирование
175

Я обнаружил, что наилучшей практикой использования изображений, видео и т. Д. Является:

  • Измените ваши файлы «Создать действие» на «Содержимое» . Обязательно установите флажок Копировать в каталог для сборки .
    • Находится в меню «Правый клик» в окне обозревателя решений.
  • Источник изображения в следующем формате:
    • «/ « YourAssemblyName » ; компонент /« YourPath »/ « YourImage.png » »

пример

<Image Source="/WPFApplication;component/Images/Start.png" />

Льготы:

  • Файлы не встраиваются в сборку.
    • Диспетчер ресурсов вызовет некоторые проблемы переполнения памяти из-за слишком большого количества ресурсов (во время сборки).
  • Можно вызывать между сборками.
Нуно Родригес
источник
36
Этот же подход работает, если вы встраиваете ресурс в сборку, но вам нужно установить для «Build Action» значение «Resource».
Эшли Дэвис
5
Работает, спасибо. Одно замечание для других: «компонент» требуется «как есть», «изображения» - это относительный путь png в проекте. Т.е. изображение, помещаемое в корень, будет "<Image Source =" / WPFApplication; component / Start.png "/>"
Badiboy
3
Пример того, как сделать это в C #, был бы хорош. (Это недопустимый URI, поэтому его нельзя использовать при создании BitmapImage.)
Vaccano
5
Итак, как вы это сделаете, если файл установлен на Embedded Resource? Это не похоже на работу. И я не хочу включать изображение в свой проект дважды. (Я уже использую его как встроенный ресурс.)
BrainSlugs83
2
Где и как «компонент» вступает на путь. Это часть какой-то спецификации?
Триынко
46

Некоторые люди спрашивают об этом в коде и не получают ответа.

Потратив много часов на поиски, я нашел очень простой метод, я не нашел ни одного примера, и поэтому я поделился здесь своим, который работает с изображениями. (мой был .gif)

Резюме:

Он возвращает BitmapFrame, который, по-видимому, нравится «получателям» ImageSource.

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

doGetImageSourceFromResource ("[YourAssemblyNameHere]", "[YourResourceNameHere]");

Метод:

static internal ImageSource doGetImageSourceFromResource(string psAssemblyName, string psResourceName)
{
    Uri oUri = new Uri("pack://application:,,,/" +psAssemblyName +";component/" +psResourceName, UriKind.RelativeOrAbsolute);
    return BitmapFrame.Create(oUri);
}

Усвоение:

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

Я надеюсь, что это спасет вас от многих часов, которые я хотел бы получить для меня!

Craig
источник
44

В коде для загрузки ресурса в исполняющую сборку, где мое изображение Freq.pngбыло в папке Iconsи определено как Resource:

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

Использование (предполагается, что вы поместили функцию в класс ResourceHelper):

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

Примечание : см. URI пакета MSDN в WPF :
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

Эрик Оуэлл
источник
new Uri выбрасывает Invalid URI: указан неверный порт.
Стив
У тебя есть оскорбление Uri?
Эрик Оуэлл
1
тот же URI, что и у вас, за исключением того, что мой работал внутри WPF winform. И схема «пачка» еще не была зарегистрирована, когда я позвонил новому Ури.
Стив
1
Ой ... это, вероятно, повторяется, чтобы winform размещал WPF. Мне жаль. Я не буду пытаться исправить это, потому что я думаю, что это не очень распространенное использование. Удачи!
Эрик Оуэлл
В моем случае использование new Uri(@"pack://application:,,,/" + pathInApplication)также сделало свое дело .
Адам Кальвет Бол
40

Да, это правильный путь.

Вы можете использовать изображение в файле ресурсов, просто используя путь:

<Image Source="..\Media\Image.png" />

Вы должны установить действие сборки файла образа на «Ресурс».

ЕМА
источник
1
Спасибо за это. Есть ли способ сделать что-то похожее с ImageSource, по сути, загрузив изображение один раз в словарь ресурсов. Я боюсь, что этот подход загружает данные изображения несколько раз в память.
Дрю Ноакс
2
Это будет беспорядок, когда вам нужно рефакторинг вашего кода. Вам придется вручную изменить все ссылки на изображения, если ваш документ xaml изменит пространство имен. Метод, описанный Дрю Ноаксом, намного более гладкий и удобный.
Каспер Холдум
14

Полное описание того, как использовать ресурсы: ресурс приложения WPF, содержимое и файлы данных.

И как ссылаться на них, читайте "Упаковать URI в WPF".

Короче говоря, есть даже средства для ссылки на ресурсы из ссылочных / ссылающихся сборок.

techfan
источник
Похоже, что ссылка живая и исправная (хотя в ней говорится «Эта документация заархивирована и не поддерживается» ).
Питер Мортенсен
5
  1. Visual Studio 2010 Professional SP1.
  2. .NET Framework 4 Профиль клиента.
  3. Изображение PNG добавлено в качестве ресурса в свойствах проекта.
  4. Новый файл в папке «Ресурсы» создается автоматически.
  5. Создайте действие для ресурса.

Это сработало для меня:

<BitmapImage x:Key="MyImageSource" UriSource="Resources/Image.png" />
JoanComasFdz
источник
3

Если вы используете Blend , чтобы сделать его более простым и не иметь проблем с получением правильного пути для атрибута Source , просто перетащите изображение с панели Project на дизайнер.

user42467
источник
3

Да, это правильный путь. Вы можете использовать изображения в файле ресурсов, используя путь:

<StackPanel Orientation="Horizontal">
    <CheckBox  Content="{Binding Nname}" IsChecked="{Binding IsChecked}"/>
    <Image Source="E:\SWorking\SharePointSecurityApps\SharePointSecurityApps\SharePointSecurityApps.WPF\Images\sitepermission.png"/>
    <TextBlock Text="{Binding Path=Title}"></TextBlock>
</StackPanel>
Санджай Ранавая
источник
-5

Следующее сработало и изображения для установки это ресурсы в свойствах:

    var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(MyProject.Properties.Resources.myImage.GetHbitmap(),
                                      IntPtr.Zero,
                                      Int32Rect.Empty,
                                      BitmapSizeOptions.FromEmptyOptions());
    MyButton.Background = new ImageBrush(bitmapSource);
img_username.Source = bitmapSource;
Рагхулан Гаутаман
источник
5
Без обид, но это пахнет плохой практикой.
ШлоЭми