Mengatur sumber gambar WPF dalam kode


325

Saya mencoba mengatur sumber gambar WPF dalam kode. Gambar tertanam sebagai sumber daya dalam proyek. Dengan melihat contoh-contoh saya telah datang dengan kode di bawah ini. Untuk beberapa alasan itu tidak berfungsi - gambar tidak muncul.

Dengan men-debug saya dapat melihat bahwa stream berisi data gambar. Jadi apa yang salah?

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;

Ikon didefinisikan seperti ini: <Image x:Name="_icon" Width="16" Height="16" />


Jika gambar di drive lokal, <Image Source="some_fully_qualified_path">di XAML tidak pernah gagal.
Laurie Stearn

@LauriePelajari intinya adalah bahwa kita tidak tahu jalan dan membutuhkan kode untuk menentukannya. Sebagai orang yang baru mengenal pemrograman Windows GUI, saya harus mengakui bahwa WinForms tampaknya lebih menarik daripada omong kosong XAML ini.
Alex Jansen

Jawaban:


416

Setelah mengalami masalah yang sama seperti Anda dan membaca, saya menemukan solusinya - Pak URI .

Saya melakukan hal berikut dalam kode:

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;

Atau lebih pendek, dengan menggunakan konstruktor BitmapImage lain:

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

URI pecah menjadi beberapa bagian:

  • Wewenang: application:///
  • Path: Nama file sumber daya yang dikompilasi ke dalam rujukan yang direferensikan. Path harus sesuai dengan format berikut:AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName: nama pendek untuk perakitan yang direferensikan.
    • ; Versi [opsional]: versi rujukan yang berisi file sumber. Ini digunakan ketika dua atau lebih majelis direferensikan dengan nama pendek yang sama dimuat.
    • ; PublicKey [opsional]: kunci publik yang digunakan untuk menandatangani rujukan yang direferensikan. Ini digunakan ketika dua atau lebih majelis direferensikan dengan nama pendek yang sama dimuat.
    • ; komponen: menetapkan bahwa majelis yang dirujuk dirujuk dari majelis lokal.
    • / Path: nama file sumber daya, termasuk path-nya, relatif terhadap akar folder proyek rakitan yang direferensikan.

Tiga garis miring setelah itu application:harus diganti dengan koma:

Catatan: Komponen otoritas paket URI adalah URI tertanam yang menunjuk ke paket dan harus sesuai dengan RFC 2396. Selain itu, karakter "/" harus diganti dengan karakter ",", dan karakter yang dipesan seperti "%" dan "?" harus melarikan diri. Lihat OPC untuk detailnya.

Dan tentu saja, pastikan Anda menetapkan action build pada gambar Anda Resource.


Ya, ini adalah solusi yang saya temukan sendiri setelah beberapa trial and error. Terima kasih atas penjelasannya. Jawaban diterima!
Torbjørn

Saya tidak tahu mengapa hal ini diperlukan meskipun, dan mengapa jawaban yang lain tidak bekerja untuk saya ...
Torbjørn

jawaban lain dalam hal ini dan pertanyaan lain juga tidak berhasil untuk saya. Yang ini bekerja dengan sempurna. Terima kasih.
Thomas Stock

9
Oke, tapi tidak adakah metode atau kelas yang digunakan parser XAML untuk mengonversi string jalur sederhana menjadi ImageSource? Tidak bisakah kita menggunakannya saja?
Qwertie

1
Saya sering melihat cuplikan ini disalin ke pos lain, di mana orang biasanya mengabaikan keberadaan BitmapImage(Uri)konstruktor, yang membantu menghindari kebutuhan untuk memanggil BeginInit dan EndInit. Saya sudah menambahkannya di sini.
Clemens

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

Ini akan memuat gambar yang disebut "Untitled.png" dalam folder yang disebut "Gambar" dengan "Build Action" yang disetel ke "Sumber Daya" dalam majelis yang disebut "WpfApplication1".


16
Terima kasih untuk itu. Satu masalah yang membuat saya tersandung sebagai noob to wpf, gambar harus ditandai sebagai sumber daya agar ini berfungsi.
si618

4
Solusi ini memberi saya pengecualian jadi saya mencoba solusi Jared Harley dan itu berhasil ...
Sangram Nandkhile

2
yang paling penting adalah "UriKind.RelativeOrAbsolute" - contoh lain selalu melempar pengecualian
Sven

9
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);akan cukup
Hamzeh Soboh

... dan lebih mudah. Terima kasih Hamzeh
pStan

74

Ini adalah kode yang sedikit lebih sedikit dan dapat dilakukan dalam satu baris.

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

8
Ini jelas merupakan jawaban terbaik, memanfaatkan implementasi .NET sendiri
joshcomley

bagaimana jika kita perlu mengatur tinggi dan lebar gambar yaitu icon.png? Karena dengan menggunakan _image.height dan _image.width itu mengatur jendela gambar bukan gambar yang sebenarnya yaitu icon.png.
secretgenes

41

Sangat mudah:

Untuk mengatur gambar item menu secara dinamis, hanya lakukan hal berikut:

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

... sedangkan "icon.ico" dapat ditemukan di mana saja (saat ini terletak di direktori 'Resources') dan harus ditautkan sebagai Resource ...


2
Lebih pendek = lebih baik. Saya harus mengaturnya sebagai @ "/ folder / image.png" tetapi kemudian bekerja dengan baik. Terima kasih!
gjvdkamp

3
Ketika saya menetapkan sumber gambar, itu hanya muncul kosong :(
HaloMediaz

Jalan @HaloMediaz mungkin salah .... mis. Anda memiliki Sumberdaya tetapi Anda dapat menuliskannya Sumber Daya
Rouzbeh Zarandi

Ini bekerja untuk saya, dan jauh lebih mudah daripada URI absolut dalam jawaban lain.
Psiloc

16

Anda juga dapat mengurangi ini menjadi satu baris. Ini adalah kode yang saya gunakan untuk mengatur Ikon untuk jendela utama saya. Ini mengasumsikan file .ico ditandai sebagai Konten dan sedang disalin ke direktori output.

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

16

Cara termudah:

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

15

Sudahkah Anda mencoba:

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

Ini cara saya:

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

Pemakaian:

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

8

Berikut adalah contoh yang menetapkan jalur gambar secara dinamis (gambar yang terletak di suatu tempat di disk daripada membangun sebagai sumber daya):

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

Refleksi pada Ikon ...

Pikiran pertama, Anda akan berpikir bahwa properti Ikon hanya dapat berisi gambar. Tetapi sebenarnya bisa mengandung apa saja! Saya menemukan ini secara tidak sengaja ketika saya mencoba untuk mengatur Imageproperti secara langsung ke string dengan path ke gambar. Hasilnya adalah itu tidak menunjukkan gambar, tetapi teks sebenarnya dari path!

Ini mengarah ke alternatif untuk tidak harus membuat gambar untuk ikon, tetapi gunakan teks dengan font simbol sebagai gantinya untuk menampilkan "ikon" sederhana. Contoh berikut menggunakan font Wingdings yang berisi simbol "floppydisk". Simbol ini benar-benar karakter <, yang memiliki arti khusus dalam XAML, jadi kita harus menggunakan versi yang disandikan &lt;. Ini bekerja seperti mimpi! Berikut ini menunjukkan simbol floppydisk sebagai ikon pada item menu:

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

Pertanyaan: " Gambar disematkan sebagai sumber daya dalam proyek ", jawab: " Berikut adalah contoh [untuk gambar] yang terletak di suatu tempat di disk daripada membangun sebagai sumber daya ".
mnt

7

Jika gambar Anda disimpan dalam ResourceDictionary, Anda dapat melakukannya hanya dengan satu baris kode:

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

6

Ada juga cara yang lebih sederhana. Jika gambar dimuat sebagai sumber daya dalam XAML, dan kode yang dimaksud adalah kode di belakang untuk konten XAML itu:

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

4

Masukkan bingkai ke dalam VisualBrush:

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

brush.Visual = frame;

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

Masukkan VisualBrush di 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;

Sekarang masukkan GeometryDrawing dalam DrawingImage:

new DrawingImage(drawing);

Tempatkan ini di sumber gambar Anda, dan voila!

Anda bisa melakukannya dengan lebih mudah:

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

Dan dalam kode:

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

LOL! Mengapa membuatnya mudah ketika Anda pertama kali dapat membuatnya menjadi sulit :) Saya akan mencoba solusi sederhana Anda sebelum saya menerimanya ...
Torbjørn

Sebenarnya ini sama sekali tidak membantu saya. Mungkin aku bodoh :( Tidak punya waktu untuk melihat lebih dekat sekarang (proyek kesayangan). Ingin mendapat lebih banyak jawaban ketika aku kembali ke sana :)
Torbjørn

3

Ada juga cara yang lebih sederhana. Jika gambar dimuat sebagai sumber daya dalam XAML, dan kode yang dimaksud adalah codebehind untuk XAML itu:

Berikut kamus sumber daya untuk file XAML - satu-satunya baris yang Anda pedulikan adalah ImageBrush dengan kunci "PosterBrush" - sisa kode hanya untuk menunjukkan konteks

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

        </ResourceDictionary>
    </UserControl.Resources>

Sekarang, dalam kode di belakang, Anda bisa melakukan ini

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

2

Cara memuat gambar dari tertanam di ikon sumber daya dan gambar (versi terkoreksi dari Arcturus):

Misalkan Anda ingin menambahkan tombol dengan gambar. Apa yang harus kamu lakukan

  1. Tambahkan ke ikon folder proyek dan letakkan gambar ClickMe.png di sini
  2. Di properti 'ClickMe.png', tetapkan 'BuildAction' menjadi 'Resource'
  3. Misalkan nama majelis Anda yang dikompilasi adalah 'Company.ProductAssembly.dll'.
  4. Sekarang saatnya memuat gambar kita di 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>

Selesai


2

Saya baru mengenal WPF, tetapi tidak di .NET.

Saya telah menghabiskan lima jam mencoba untuk menambahkan file PNG ke "Proyek Perpustakaan Kontrol Kontrol WPF" di. NET 3.5 (Visual Studio 2010) dan menetapkannya sebagai latar belakang kontrol yang diwarisi gambar.

Tidak ada yang relatif dengan URI bekerja. Saya tidak bisa membayangkan mengapa tidak ada metode untuk mendapatkan URI dari file sumber daya, melalui IntelliSense, mungkin sebagai:

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

Saya sudah mencoba banyak URI dan bermain dengan ResourceManager, dan metode GetManifest Assembly, tetapi semua ada pengecualian atau nilai NULL.

Di sini saya membuat kode yang berfungsi untuk saya:

// 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
Saya pikir masalahnya adalah bahwa WPF tidak "suka" pendekatan tradisional menempatkan sumber daya dalam file resx. Alih-alih, Anda seharusnya menambahkan gambar langsung ke proyek Anda dan mengatur properti Build Action-nya menjadi Resource. Saya tidak tahu apa bedanya (dalam format file fisik) antara kedua pendekatan.
Qwertie

1
Pastikan Build Build is Content
Jerry Nixon

1

Jika Anda sudah memiliki aliran dan mengetahui formatnya, Anda dapat menggunakan sesuatu seperti ini:

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

1

Anda baru saja melewatkan sedikit.

Untuk mendapatkan sumber daya yang tertanam dari majelis apa pun, Anda harus menyebutkan nama majelis dengan nama file Anda seperti yang telah saya sebutkan di sini:

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 () tampaknya tidak ada di WPF.
Myosotis

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.