Установка источника изображения WPF в коде

Я пытаюсь установить исходный код изображения 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" />


person Torbjørn    schedule 08.12.2008    source источник
comment
Если образ находится на локальном диске, <Image Source="some_fully_qualified_path"> в XAML никогда не дает сбоев.   -  person Laurie Stearn    schedule 31.12.2017
comment
@LaurieStearn, все дело в том, что мы не знаем путь и нам нужен код для его определения. Как новичок в программировании графического интерфейса Windows, я должен признать, что WinForms кажется более привлекательным, чем эта чушь XAML.   -  person Alex Jansen    schedule 30.03.2019


Ответы (19)


После того, как я столкнулся с той же проблемой, что и вы, и немного почитал, я нашел решение - Упаковать 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: the short name for the referenced assembly.
    • ; Версия [необязательно]: версия сборки, на которую указывает ссылка, которая содержит файл ресурсов. Это используется, когда загружаются две или более сборки, на которые есть ссылки, с одинаковым коротким именем.
    • ; PublicKey [необязательно]: открытый ключ, который использовался для подписи указанной сборки. Это используется, когда загружаются две или более ссылочных сборки с одинаковым коротким именем.
    • ; component: указывает, что указанная сборка ссылается на локальную сборку.
    • / Путь: имя файла ресурсов, включая его путь, относительно корня папки проекта сборки, на которую имеется ссылка.

Три слэша после application: необходимо заменить запятыми:

Примечание. Компонент полномочий в URI пакета - это встроенный URI, который указывает на пакет и должен соответствовать RFC 2396. Кроме того, символ «/» должен быть заменен символом «,» и зарезервированными символами, такими как «%» а также "?" нужно избежать. Подробности см. В OPC.

И, конечно же, убедитесь, что вы установили действие сборки для своего изображения на Resource.

person Jared Harley    schedule 30.10.2009
comment
Да, это было решение, которое я нашел после некоторых проб и ошибок. Спасибо за подробное объяснение. Ответ принят! - person Torbjørn; 04.11.2009
comment
Я не знаю, зачем это было нужно, и почему другие ответы не помогли мне ... - person Torbjørn; 04.11.2009
comment
другие ответы на этот и другие вопросы тоже не помогли мне. Этот отлично работает. Спасибо. - person Thomas Stock; 27.03.2010
comment
Хорошо, но нет ли какого-либо метода или класса, который анализатор XAML использует для преобразования простой строки пути в ImageSource? Не могли бы мы просто использовать это? - person Qwertie; 02.06.2011
comment
У меня это решение не работает. Я получаю ошибку компиляции: _1 _... - person Scott Solmer; 24.07.2014
comment
Добавьте изображение в сетку из панели инструментов, добавьте к нему имя (например, TestImage) и установите путь к изображению в меню свойств. Затем напишите var testImage = TestImage в код запуска, добавьте точку останова, выполните отладку и скопируйте исходное значение. - person hkarask; 06.11.2014
comment
Я часто вижу этот фрагмент, скопированный в другие сообщения, где люди обычно игнорируют существование конструктора BitmapImage(Uri), что помогает избежать необходимости вызывать BeginInit и EndInit. Я добавил это сюда. - person Clemens; 07.11.2017
comment
Откуда мне взять название сборки? - person Yessir; 17.02.2021

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

Это загрузит изображение с именем «Untitled.png» в папку с именем «Images» с его «Действие сборки», установленное на «Ресурс» в сборке с именем «WpfApplication1».

person Simon    schedule 26.08.2009
comment
Спасибо за это. Одна проблема, из-за которой я споткнулся как новичок в wpf, изображение должно быть помечено как ресурс, чтобы это работало. - person si618; 31.10.2009
comment
Это решение дало мне исключение, поэтому я попробовал решение Джареда Харли, и оно сработало ... - person Sangram Nandkhile; 08.04.2011
comment
самое главное - UriKind.RelativeOrAbsolute - в других примерах всегда возникали исключения - person Sven; 03.04.2012
comment
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative); будет достаточно - person Hamzeh Soboh; 05.07.2013
comment
... и намного проще. Спасибо Хамзе - person pStan; 05.02.2015
comment
Это решение не сработало для меня, но добавление pack://application:,,, в Uri работает. - person Slate; 14.02.2019

Это немного меньше кода и может быть выполнен в одной строке.

string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;
person Alex B    schedule 06.01.2010
comment
Это определенно лучший ответ, использующий собственную реализацию .NET. - person joshcomley; 27.04.2014
comment
что, если нам нужно установить высоту и ширину изображения, то есть icon.png? Потому что, используя _image.height и _image.width, он устанавливает окно изображения, а не фактическое изображение, то есть icon.png. - person secretgenes; 18.02.2016

Очень просто:

Чтобы динамически установить изображение пункта меню, выполните только следующие действия:

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

... тогда как "icon.ico" может быть расположен повсюду (в настоящее время он находится в каталоге "Ресурсы") и должен быть связан как Ресурс ...

person A Bothe    schedule 12.12.2010
comment
Короче = лучше. Мне пришлось установить его как @ / folder / image.png, но тогда он работал нормально. Спасибо! - person gjvdkamp; 22.02.2011
comment
Когда я назначаю источник изображения, он просто отображается пустым :( - person HaloMediaz; 03.03.2016
comment
Путь @HaloMediaz может быть неправильным .... например, у вас есть ресурсы, но вы можете написать его Resource - person Rouzbeh Zarandi; 02.10.2018
comment
Это сработало для меня и намного проще, чем абсолютные URI в других ответах. - person Psiloc; 06.11.2018

Самый простой способ:

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

Вы также можете сократить это до одной строки. Это код, который я использовал для установки значка для моего главного окна. Предполагается, что ICO-файл помечен как Content и копируется в выходной каталог.

 this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));
person Payson Welch    schedule 13.02.2011

Ты пробовал:

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

Это мой путь:

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"))
person IlPADlI    schedule 09.05.2015

Если ваше изображение хранится в ResourceDictionary, вы можете сделать это с помощью только одной строки кода:

MyImage.Source = MyImage.FindResource("MyImageKeyDictionary") as ImageSource;
person Hollyroody    schedule 15.05.2017

Вот пример, который динамически устанавливает путь к изображению (изображение находится где-то на диске, а не создается как ресурс):

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>
person Community    schedule 10.07.2009
comment
Вопрос: Изображение встроено в проект как ресурс, ответ: Вот пример [для изображения], расположенного где-то на диске, а не построенного как ресурс. - person mins; 29.09.2019

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

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

Поместите рамку в 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 в DrawingImage:

new DrawingImage(drawing);

Поместите это в свой источник изображения, и вуаля!

Но вы могли бы сделать это намного проще:

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

И в коде:

BitmapImage image = new BitmapImage { UriSource="/yourassembly;component/YourImage.PNG" };
person Arcturus    schedule 08.12.2008
comment
РЖУ НЕ МОГУ! Зачем упрощать, если вы сначала можете усложнить ситуацию :) Я попробую ваше простое решение, прежде чем приму ... - person Torbjørn; 09.12.2008
comment
На самом деле мне это совсем не помогло. Может, я тупой :( У меня нет времени сейчас присмотреться (проект питомца). Хотел бы больше ответов, когда я вернусь к нему :) - person Torbjørn; 09.12.2008

Есть и более простой способ. Если изображение загружается как ресурс в 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"];
person Mark Mullin    schedule 15.01.2010

Как загрузить изображение из встроенных в ресурсы значков и изображений (исправленная версия Arcturus):

Предположим, вы хотите добавить кнопку с изображением. Что вы должны сделать?

  1. Добавьте в папку проекта иконки и поместите сюда картинку ClickMe.png
  2. В свойствах ClickMe.png установите для BuildAction значение Resource.
  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>
    

Выполнено.

person Siarhei Kuchuk    schedule 24.03.2010

Я новичок в WPF, но не в .NET.

Я потратил пять часов, пытаясь добавить файл PNG в «Проект библиотеки настраиваемых элементов управления WPF» в .NET 3.5 (Visual Studio 2010) и установить его в качестве фона для элемента управления, унаследованного от изображения.

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

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

Я пробовал много URI и играл с методами ResourceManager и Assembly 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;
person JoanComasFdz    schedule 04.07.2010
comment
Я думаю, проблема в том, что WPF не нравится традиционный подход к размещению ресурсов в файлах resx. Вместо этого вы должны добавить изображение непосредственно в свой проект и установить для его свойства Build Action значение Resource. Я не знаю, в чем разница (в терминах физического формата файла) между этими двумя подходами. - person Qwertie; 03.06.2011
comment
Убедитесь, что действие сборки - это содержимое - person Jerry Nixon; 18.11.2011

Если у вас уже есть поток и вы знаете формат, вы можете использовать что-то вроде этого:

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

Вы просто немного упустили.

Чтобы получить встроенный ресурс из любой сборки, вы должны указать имя сборки с именем вашего файла, как я уже упоминал здесь:

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;
person maulik kansara    schedule 11.04.2015
comment
BeginInit (), похоже, не существует в WPF. - person Myosotis; 24.11.2016
comment
Это доступно, проверьте ссылку ниже msdn.microsoft.com/en-us/library/ - person maulik kansara; 24.11.2016

Вот если вы хотите разместить его рядом с исполняемым файлом (относительно исполняемого файла)

img.Source = new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + @"\Images\image.jpg", UriKind.Absolute));
person Donovan Phoenix    schedule 11.10.2020

Force выбрал UriKind будет правильным:

Image.Source = new BitmapImage(new Uri("Resources/processed.png", UriKind.Relative));

Варианты UriKind:

UriKind.Relative // relative path
UriKind.Absolute // exactly path
person VinaCaptcha    schedule 28.06.2021