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


408

Я в основному з Інтернету та трохи тла Windows Forms. Для нового проекту ми будемо використовувати WPF. Додаток WPF знадобиться 10 - 20 маленьких піктограм та зображень для ілюстративних цілей. Я думаю про збереження їх у складі як вбудованих ресурсів. Це правильний шлях?

Як я можу вказати в XAML, що елемент керування зображенням повинен завантажувати зображення із вбудованого ресурсу?

Відповіді:


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.MergedDic Dictionary> <ResourceDictionary Source = "Dictionary1.xaml" /> </ResourceDictionary.MergedDic Dictionary> </ResourceDictionary> </UserControl.Resources>
Dan Mitchell

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
невдале програмування

174

Найкращою практикою використання зображень, відеозаписів і т.д. я вважаю:

  • Змініть свої файли "Збірка дії" на "Зміст" . Не забудьте перевірити Копіювати для створення каталогу .
    • Знаходиться в меню "Клацніть правою кнопкою миші" у вікні Провідника рішень.
  • Джерело зображення у такому форматі:
    • "/ " YourAssemblyName " ; компонент /« YourPath »/ « YourImage.png » "

Приклад

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

Переваги:

  • Файли не вбудовуються в збірку.
    • Менеджер ресурсів підніме деякі проблеми із переповненням пам’яті із занадто великою кількістю ресурсів (під час створення).
  • Можна викликати між складами.

36
Цей самий підхід працює, якщо ви вставляєте ресурс у збірку, але вам потрібно встановити "Дія збірки" на "Ресурс".
Ешлі Девіс

5
Працює, дякую. Одна примітка для інших: "компонент" потрібен "як є", "Зображення" - відносний шлях png у проекті. Тобто зображення, розміщене в корені, буде "<Source Source =" / WPFApplication; компонент / Start.png "/>"
Badiboy

3
Приклад того, як це зробити в C #, було б непогано. (Це неправдивий URI, тому його не можна використовувати при побудові BitmapImage.)
Vaccano

5
Отже, як це зробити, якщо файл встановлений на Вбудований ресурс? Це, здається, не працює. І я не хочу двічі включати зображення у свій проект. (Я вже використовую його як вбудований ресурс.)
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);
}

Навчання:

З мого досвіду, рядок пакету не є проблемою, перевірте свої потоки, і особливо, якщо читати його вперше встановив покажчик в кінці файлу, і вам потрібно знову встановити його на нуль, перш ніж читати знову.

Я сподіваюся, що це заощадить вам багато годин, які я хотів би, щоб ця штука мала для мене!


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


новий Uri кидає Недійсний URI: Недійсний порт вказаний.
Стів

У вас є ури-кривди?
Ерік Оуеллет

1
такі ж урі, як і у вас, за винятком того, що моя шахта працювала всередині WPF, на якому розміщена winform. І схема "pack" ще не була зареєстрована, коли я зателефонував до нового Uri.
Стів

1
На жаль, це, мабуть, відреаговано на програму WPF, що приймає winform. Мені шкода. Я не намагаюся це виправити, бо думаю, що це не дуже поширене використання. Удачі!
Ерік Оуеллет

У моєму випадку, використовуючи new Uri(@"pack://application:,,,/" + pathInApplication)також зробив трюк.
Адам

40

Так, це правильний шлях.

Ви можете використовувати зображення у файлі ресурсу, просто використовуючи шлях:

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

Потрібно встановити дію файлу зображення на "Ресурс".


1
Дякую за це Чи є спосіб зробити щось подібне із ImageSource, фактично завантаживши зображення один раз у словник ресурсів. Я побоююся, що такий підхід кілька разів завантажує дані зображення в пам'ять.
Дрю Ноакс

2
Це буде безлад, коли вам потрібно переробити код. Вам доведеться вручну змінити всі посилання на зображення, якщо ваш Xaml документ змінить простір імен. Метод, описаний Дрю Ноаксом, набагато більш гладкий і практичний.
Каспер Холдум

14

Повний опис використання ресурсів: ресурсів, вмісту та файлів даних WPF

А як посилатися на них, читайте у "Пакеті URI у WPF".

Коротше кажучи, є навіть засоби для посилання на ресурси з посилальних / референтних зборів.


Здається, посилання є активним (хоча там написано "Ця документація архівується і не підтримується." ).
Пітер Мортенсен

5
  1. Visual Studio 2010 Professional SP1.
  2. Профіль клієнта .NET Framework 4.
  3. Зображення PNG додано як ресурс щодо властивостей проекту.
  4. Новий файл у папці Ресурси створено автоматично.
  5. Побудувати дію, встановлену на ресурс.

Це працювало для мене:

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

3

Якщо ви використовуєте Blend , щоб зробити це надзвичайно просто і не мати ніяких проблем з правильним шляхом для атрибута Source , просто перетягніть зображення з панелі Project на дизайнер.


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
Без образи, але це пахне поганою практикою.
ShloEmi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.