Встановлення джерела зображення WPF у коді


325

Я намагаюся встановити в коді джерело зображення WPF. Зображення вбудовується як ресурс у проект. Переглядаючи приклади, я придумав наведений нижче код. Чомусь це не працює - зображення не відображається.

За допомогою налагодження я бачу, що потік містить дані зображення. Отже, що не так?

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
PngBitmapDecoder iconDecoder = new PngBitmapDecoder(iconStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
ImageSource iconSource = iconDecoder.Frames[0];
_icon.Source = iconSource;

Піктограма визначається приблизно так: <Image x:Name="_icon" Width="16" Height="16" />


Якщо зображення знаходиться на локальному диску, <Image Source="some_fully_qualified_path">XAML ніколи не виходить з ладу.
Лорі Стерн

@LaurieStearn вся справа в тому, що ми не знаємо шлях і код потрібен для того, щоб визначити його. Як хтось новий у програмі Windows GUI, я мушу визнати, що WinForms здається більш привабливим, ніж це лайно XAML.
Алекс Янсен

Відповіді:


416

Виникнувши з тією ж проблемою, що і у вас, і я прочитав читання, я знайшов рішення - URI-пакети .

Я зробив наступне в коді:

Image finalImage = new Image();
finalImage.Width = 80;
...
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png");
logo.EndInit();
...
finalImage.Source = logo;

Або коротше, використовуючи інший конструктор BitmapImage:

finalImage.Source = new BitmapImage(
    new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png"));

URI розбивається на частини:

  • Орган: application:///
  • Шлях: ім'я файлу ресурсу, який компілюється у посилальну збірку. Шлях повинен відповідати наступному формату:AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName: коротке ім'я посилальної збірки.
    • Версія [необов'язково]: версія посилальної збірки, що містить файл ресурсу. Це використовується, коли завантажуються дві або більше посилальних збірок з однаковим коротким ім'ям.
    • ; PublicKey [необов’язково]: відкритий ключ, який використовувався для підписання посилальної збірки. Це використовується, коли завантажуються дві або більше посилальних збірок з однаковим коротким ім'ям.
    • ; компонент: вказує, що на збірку, на яку посилається, посилається місцева збірка.
    • / Шлях: ім'я файлу ресурсу, включаючи його шлях, відносно кореня папки проектів проекту з посиланням.

Три косої риски після application:цього потрібно замінити комами:

Примітка: Компонент авторитету URI пакета - це вбудований URI, який вказує на пакет і повинен відповідати RFC 2396. Крім того, символ "/" повинен бути замінений символами "," та зарезервованими символами, такими як "%" і "?" треба уникати. Детальніше дивіться в OPC.

І звичайно, переконайтеся, що ви встановили дію збірки для свого зображення Resource.


Так, саме таке рішення я знайшов після деяких спроб та помилок. Дякую за ретельне пояснення. Відповідь прийнято!
Torbjørn

Я не знаю, навіщо це було потрібно, і чому інші відповіді не спрацювали для мене ...
Torbjørn

інші відповіді на це та інші запитання також не працювали для мене. Цей ідеально працює. Дякую.
Томас Сток

9
Гаразд, але чи не існує якогось методу чи класу, який аналізатор XAML використовує для перетворення рядка простого шляху в ImageSource? Чи не могли ми просто цим скористатися?
Qwertie

1
Я часто бачу цей фрагмент, скопійований в інші пости, де люди зазвичай ігнорують існування BitmapImage(Uri)конструктора, що допомагає уникнути необхідності виклику BeginInit та EndInit. Я додав його сюди.
Клеменс

175
var uriSource = new Uri(@"/WpfApplication1;component/Images/Untitled.png", UriKind.Relative);
foo.Source = new BitmapImage(uriSource);

Це завантажить зображення під назвою "Untitled.png" у папку під назвою "Образи", а "Збірка дії" встановлена ​​на "Ресурс" у складі під назвою "WpfApplication1".


16
Дякую за це. Одне питання, яке спричинило мене як noob to wpf, зображення повинно бути позначене як ресурс для цього.
si618

4
Це рішення дало мені виняток, тому я спробував рішення Джареда Харлі, і воно спрацювало ...
Sangram Nandkhile

2
найголовніше - "UriKind.RelativeOrAbsolute" - інші приклади завжди кидали винятки
Sven

9
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);було б достатньо
Hamzeh Soboh

... і набагато простіше. Дякую Гамзе
пСтан

74

Це трохи менше коду і його можна зробити в одному рядку.

string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;

8
Це, безумовно, найкраща відповідь, використовуючи власну реалізацію
.NETs

що робити, якщо нам потрібно встановити висоту та ширину зображення, тобто icon.png? Тому що, використовуючи _image.height та _image.width, він встановлює вікно зображення не власне зображення, тобто icon.png.
secretgenes

41

Дуже легко:

Щоб динамічно встановити зображення елемента меню, виконайте лише такі дії:

MyMenuItem.ImageSource = 
    new BitmapImage(new Uri("Resource/icon.ico",UriKind.Relative));

... тоді як "icon.ico" може бути розташований скрізь (зараз він знаходиться в каталозі "Ресурси") і повинен бути пов'язаний як Ресурс ...


2
Коротше = краще. Мені довелося встановити його як @ "/ folder / image.png", але тоді він працював нормально. Дякую!
gjvdkamp

3
Коли я призначаю джерело зображень, він просто з’являється порожнім :(
HaloMediaz

@HaloMediaz шлях може бути неправильним .... наприклад, у вас є ресурси, але ви можете написати це ресурс
Rouzbeh Zarandi

Це працювало для мене, і набагато простіше, ніж абсолютні URI в інших відповідях.
Psiloc

16

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

 this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));

16

Найпростіший спосіб:

var uriSource = new Uri("image path here");
image1.Source = new BitmapImage(uriSource);

15

Ти намагався:

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
_icon.Source = bitmap;

13

Це мій шлях:

internal static class ResourceAccessor
{
    public static Uri Get(string resourcePath)
    {
        var uri = string.Format(
            "pack://application:,,,/{0};component/{1}"
            , Assembly.GetExecutingAssembly().GetName().Name
            , resourcePath
        );

        return new Uri(uri);
    }
}

Використання:

new BitmapImage(ResourceAccessor.Get("Images/1.png"))

8

Ось приклад, який динамічно встановлює шлях зображення (зображення розташоване десь на диску, а не будується як ресурс):

if (File.Exists(imagePath))
{
    // Create image element to set as icon on the menu element
    Image icon = new Image();
    BitmapImage bmImage = new BitmapImage();
    bmImage.BeginInit();
    bmImage.UriSource = new Uri(imagePath, UriKind.Absolute);
    bmImage.EndInit();
    icon.Source = bmImage;
    icon.MaxWidth = 25;
    item.Icon = icon;
}

Роздуми про ікони ...

По-перше, ви подумаєте, що властивість Icon може містити лише зображення. Але він насправді може містити що завгодно! Я виявив це випадково, коли я програмно намагався встановити Imageвластивість прямо на рядок із шляхом до зображення. У результаті вийшло не зображення, а власне текст шляху!

Це призводить до альтернативи не потрібно робити зображення для піктограми, а використовувати текст із шрифтом символу замість цього, щоб відобразити просту «іконку». У наступному прикладі використовується шрифт Wingdings, який містить символ "дискети". Цей символ справді є символом <, який має особливе значення в XAML, тому нам доведеться використовувати &lt;замість нього закодовану версію . Це працює як мрія! Далі показано символ дискети як значок на пункті меню:

<MenuItem Name="mnuFileSave" Header="Save" Command="ApplicationCommands.Save">
  <MenuItem.Icon>
    <Label VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Wingdings">&lt;</Label>
  </MenuItem.Icon>
</MenuItem>

Питання: " Зображення вбудоване як ресурс у проект ", відповідь: " Ось приклад [для зображення], який знаходиться десь на диску, а не будується як ресурс ".
хвилини

7

Якщо ваше зображення зберігається у ResourceDictionary, ви можете зробити це лише одним рядком коду:

MyImage.Source = MyImage.FindResource("MyImageKeyDictionary") as ImageSource;

6

Існує також простіший спосіб. Якщо зображення завантажується як ресурс у XAML, а відповідний код є позаду коду для цього вмісту XAML:

Uri iconUri = new Uri("pack://application:,,,/ImageNAme.ico", UriKind.RelativeOrAbsolute);
NotifyIcon.Icon = BitmapFrame.Create(iconUri);

4

Помістіть кадр у VisualBrush:

VisualBrush brush = new VisualBrush { TileMode = TileMode.None };

brush.Visual = frame;

brush.AlignmentX = AlignmentX.Center;
brush.AlignmentY = AlignmentY.Center;
brush.Stretch = Stretch.Uniform;

Поставте VisualBrush в GeometryDrawing

GeometryDrawing drawing = new GeometryDrawing();

drawing.Brush = brush;

// Brush this in 1, 1 ratio
RectangleGeometry rect = new RectangleGeometry { Rect = new Rect(0, 0, 1, 1) };
drawing.Geometry = rect;

Тепер помістіть GeometryDrawing у малюнок малюнка:

new DrawingImage(drawing);

Розмістіть це на своєму джерелі зображення та voilà!

Ви можете зробити це набагато простіше, хоча:

<Image>
    <Image.Source>
        <BitmapImage UriSource="/yourassembly;component/YourImage.PNG"></BitmapImage>
    </Image.Source>
</Image>

І в коді:

BitmapImage image = new BitmapImage { UriSource="/yourassembly;component/YourImage.PNG" };

ЛОЛ! Навіщо робити це просто, коли вперше це може зробити це складно :) Я спробую ваше просте рішення, перш ніж я прийму, хоча ...
Torbjørn

Насправді це мені зовсім не допомогло. Можливо, я дурний :( Не маю часу зараз уважніше придивитися (проект для домашніх тварин). Хотілося б більше відповідей, коли я повернусь до нього :)
Torbjørn

3

Існує також простіший спосіб. Якщо зображення завантажується як ресурс у XAML, а відповідний код є кодом, що стоїть за цим XAML:

Ось словник ресурсів для файлу XAML - єдиний рядок, який вас хвилює, це ImageBrush з клавішею "PosterBrush" - решта коду лише для того, щоб показати контекст

<UserControl.Resources>
        <ResourceDictionary>
            <ImageBrush x:Key="PosterBrush" ImageSource="..\Resources\Images\EmptyPoster.jpg" Stretch="UniformToFill"/>

        </ResourceDictionary>
    </UserControl.Resources>

Тепер у коді позаду ви можете просто це зробити

ImageBrush posterBrush = (ImageBrush)Resources["PosterBrush"];

2

Як завантажити зображення із вбудованих у піктограми та зображення ресурсів (виправлена ​​версія Арктура):

Припустимо, ви хочете додати кнопку із зображенням. Шо тобі варто зробити?

  1. Додайте до піктограм папки проекту та поставте тут зображення ClickMe.png
  2. У властивостях "ClickMe.png" встановіть для "BuildAction" значення "Ресурс"
  3. Припустимо, ваша складена назва збірки - "Company.ProductAssembly.dll".
  4. Тепер прийшов час завантажити наше зображення в XAML

    <Button Width="200" Height="70">
      <Button.Content>
        <StackPanel>
          <Image Width="20" Height="20">
            <Image.Source>
              <BitmapImage UriSource="/Company.ProductAssembly;component/Icons/ClickMe.png"></BitmapImage>
              </Image.Source>
          </Image>
          <TextBlock HorizontalAlignment="Center">Click me!</TextBlock>
        </StackPanel>
      </Button.Content>
    </Button>

Зроблено.


2

Я новачок у WPF, але не в .NET.

Я провів п’ять годин, намагаючись додати файл PNG до "Проекту користувальницької бібліотеки керування WPF" в ​​.NET 3.5 (Visual Studio 2010) і встановивши його як фон управління, успадкованого зображеннями.

Нічого відносного з URI не працювало. Я не уявляю, чому не існує методу отримання URI з файлу ресурсу через IntelliSense, можливо, як:

Properties.Resources.ResourceManager.GetURI("my_image");

Я спробував багато URI і грав з методами ResManager та GetManifest асамблеї, але все були винятки або значення NULL.

Ось я підписую код, який працював на мене:

// Convert the image in resources to a Stream
Stream ms = new MemoryStream()
Properties.Resources.MyImage.Save(ms, ImageFormat.Png);

// Create a BitmapImage with the stream.
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.EndInit();

// Set as source
Source = bitmap;

3
Я думаю, що проблема полягає в тому, що WPF не «любить» традиційний підхід до розміщення ресурсів у resx-файлах. Натомість ви повинні додати зображення безпосередньо до свого проекту та встановити його властивість Build Action на Resource. Я не знаю, в чому різниця (у терміні фізичного формату файлу) між двома підходами.
Кверті

1
Переконайтеся, що збірка дій є вмістом
Джеррі Ніксон

1

Якщо у вас вже є потік і ви знаєте формат, ви можете використовувати щось подібне:

static ImageSource PngStreamToImageSource (Stream pngStream) {
    var decoder = new PngBitmapDecoder(pngStream,
        BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    return decoder.Frames[0];
}

1

Ви просто трохи пропустили.

Щоб отримати вбудований ресурс з будь-якої збірки, ви повинні згадати ім'я збірки із своїм ім'ям файлу, як я вже згадував тут:

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream(asm.GetName().Name + "." + "Desert.jpg");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
image1.Source = bitmap;

Схоже, BeginInit () не існує в WPF.
Міосотіс

Доступна перевірка нижче за посиланням msdn.microsoft.com/en-us/library/…
maulik kansara
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.