Sumber gambar WPF

408

Saya berasal dari sebagian besar web dan sedikit latar belakang Windows Forms. Untuk proyek baru, kami akan menggunakan WPF. Aplikasi WPF akan membutuhkan 10 - 20 ikon dan gambar kecil untuk tujuan ilustrasi. Saya berpikir tentang menyimpan ini di majelis sebagai sumber daya tertanam. Apakah itu cara yang benar untuk pergi?

Bagaimana cara menentukan di XAML bahwa kontrol Gambar harus memuat gambar dari sumber daya yang disematkan?

driis
sumber

Jawaban:

473

Jika Anda akan menggunakan gambar di banyak tempat, maka ada baiknya memuat data gambar hanya sekali ke dalam memori dan kemudian membagikannya di antara semua Imageelemen.

Untuk melakukan ini, buat BitmapSource sebagai sumber daya di suatu tempat:

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

Kemudian, dalam kode Anda, gunakan sesuatu seperti:

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

Dalam kasus saya, saya menemukan bahwa saya harus mengatur Image.pngfile agar memiliki action build Resourcebukan hanya Content. Ini menyebabkan gambar untuk dibawa dalam kompilasi yang Anda kompilasi.

Drew Noakes
sumber
6
Apakah mungkin untuk melakukan ini secara dinamis? Jika saya memiliki jumlah gambar yang berbeda yang ingin saya muat saat start-up, dapatkah saya membuat BitmapSource per gambar dan merujuknya dengan cara yang sama seperti di atas?
Becky Franklin 4-10
2
@Becky - Ya Anda bisa, meskipun jika Anda ingin merujuk mereka di Xaml maka Anda mungkin perlu menggunakan DynamicResourceekstensi markup alih-alih StaticResource, dengan asumsi Anda akan tahu kunci pada waktu kompilasi. Di WPF Anda dapat membuat kamus sumber daya saat runtime. Bahkan, itulah yang terjadi ketika Anda memuat dokumen Xaml, hanya saja Anda tidak melihat C # yang setara.
Drew Noakes
9
Sesuatu yang saya tekan: jika Anda menambahkan sumber daya gambar Anda ke kamus sumber daya, jangan lupa untuk merujuk ke kamus gambar di XAML untuk komponen Anda. Sesuatu seperti: <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source = "Dictionary1.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </UserControl.Resources>
Dan Mitchell
4
Saya biasanya menambahkan Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" ke Image, karena kalau saya sering melihat gambar mendapatkan aneh sekali ditingkatkan untuk beberapa alasan (seperti 16x16 ikon membentang untuk sesuatu yang tampak seperti 200x200 piksel).
ATAU Mapper
5
Saya menemukan bahwa jika BitmapImage dideklarasikan dalam resourcedictionary majelis referensi yang direferensikan, UriSource perlu menjadi paketUR untuk menjalankannya. Jika tidak, Anda akan menemukan bahwa Anda dapat melihat gambar di editor xaml Anda di VS tetapi tidak ada gambar saat debugging. Kemas URIS: msdn.microsoft.com/en-au/library/aa970069(v=vs.100).aspx
Gagal Memprogram
174

Saya menemukan praktik terbaik menggunakan gambar, video, dll. Adalah:

  • Ubah file Anda "Buat aksi" menjadi "Konten" . Pastikan untuk memeriksa Salin untuk membangun direktori .
    • Ditemukan di menu "Klik Kanan" di jendela Solution Explorer.
  • Sumber Gambar dalam format berikut:
    • "/ « YourAssemblyName » ; komponen /« YourPath »/ « YourImage.png » "

Contoh

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

Manfaat:

  • File tidak tertanam ke dalam rakitan.
    • Manajer Sumber Daya akan meningkatkan beberapa masalah kelebihan memori dengan terlalu banyak sumber daya (saat membangun).
  • Dapat dipanggil antar majelis.
Nuno Rodrigues
sumber
36
Pendekatan yang sama ini berfungsi jika Anda menanamkan sumber daya di majelis, tetapi Anda harus mengatur "Bangun Tindakan" menjadi "Sumber Daya".
Ashley Davis
5
Bekerja, terima kasih. Satu catatan untuk yang lain: "komponen" diperlukan "sebagaimana adanya", "Gambar" adalah jalur relatif png dalam proyek. Yaitu gambar yang ditempatkan di root akan menjadi "<Image Source =" / WPFApplication; component / Start.png "/>"
Badiboy
3
Contoh cara melakukan ini di C # akan lebih baik. (Itu bukan URI yang valid sehingga tidak dapat digunakan saat membangun BitmapImage.)
Vaccano
5
Jadi, bagaimana Anda melakukannya jika file diatur ke Sumber Daya Tertanam? Ini sepertinya tidak berhasil. Dan saya tidak ingin memasukkan gambar dalam proyek saya dua kali. (Saya sudah menggunakannya sebagai sumber daya tertanam.)
BrainSlugs83
2
Di mana dan bagaimana "komponen" masuk ke jalur. Apakah itu bagian dari beberapa spesifikasi?
Triynko
46

Beberapa orang bertanya tentang melakukan ini dalam kode dan tidak mendapatkan jawaban.

Setelah menghabiskan berjam-jam mencari saya menemukan metode yang sangat sederhana, saya tidak menemukan contoh dan jadi saya membagikan milik saya di sini yang berfungsi dengan gambar. (Milik saya adalah .gif)

Ringkasan:

Ia mengembalikan BitmapFrame yang tampaknya disukai "ImageSource".

Menggunakan:

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

Metode:

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

Belajar:

Dari pengalaman saya, string paket bukanlah masalahnya, periksa aliran Anda dan terutama jika membacanya pertama kali telah menetapkan pointer ke akhir file dan Anda perlu mengatur ulang ke nol sebelum membaca lagi.

Saya harap ini menyelamatkan Anda berjam-jam saya berharap bagian ini punya untuk saya!

Craig
sumber
44

Dalam kode untuk memuat sumber daya di rakitan pelaksana tempat gambar saya Freq.pngberada di folder Iconsdan didefinisikan sebagai Resource:

this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/" 
    + Assembly.GetExecutingAssembly().GetName().Name 
    + ";component/" 
    + "Icons/Freq.png", UriKind.Absolute)); 

Saya juga membuat fungsi:

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

Penggunaan (asumsi Anda menempatkan fungsi dalam kelas ResourceHelper):

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

Catatan : lihat URI Paket MSDN di WPF :
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

Eric Ouellet
sumber
Uri baru melempar URI Tidak Valid: Port tidak valid ditentukan.
Steve
Apakah Anda memiliki uri yang menyinggung?
Eric Ouellet
1
uri yang sama seperti milik Anda kecuali milik saya yang berjalan di dalam WPF yang di-host winform. Dan skema "paket" belum terdaftar ketika saya menelepon Uri baru.
Steve
1
Ups ... mungkin dikembalikan ke winform yang diinangi WPF. Maafkan saya. Saya tidak akan mencoba memperbaikinya karena saya pikir itu bukan penggunaan yang sangat umum. Semoga berhasil!
Eric Ouellet
Dalam kasus saya, menggunakan new Uri(@"pack://application:,,,/" + pathInApplication)juga berhasil.
Adam Calvet Bohl
40

Ya, itu jalan yang benar.

Anda bisa menggunakan gambar di file sumber daya hanya menggunakan jalur:

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

Anda harus mengatur aksi build file gambar ke "Resource".

ema
sumber
1
Terima kasih untuk ini. Apakah ada cara untuk melakukan sesuatu yang mirip dengan ImageSource, pada dasarnya memuat gambar sekali ke kamus sumber daya. Saya takut pendekatan ini memuat data gambar beberapa kali dalam memori.
Drew Noakes
2
Ini akan berantakan ketika Anda perlu memperbaiki kode Anda. Anda harus mengubah semua referensi gambar secara manual jika dokumen xaml Anda mengubah ruang nama. Metode yang dijelaskan oleh Drew Noakes jauh lebih halus dan dapat dipelihara.
Kasper Holdum
14

Deskripsi lengkap cara menggunakan sumber daya: Sumber Daya Aplikasi WPF, Konten, dan File Data

Dan bagaimana referensi mereka, baca "Kemas URI di WPF".

Singkatnya, bahkan ada sumber daya referensi dari majelis referensi / referensi.

techfan
sumber
Tautan tersebut tampaknya hidup dan baik (meskipun dikatakan "Dokumentasi ini diarsipkan dan tidak dikelola." ).
Peter Mortensen
5
  1. Visual Studio 2010 Professional SP1.
  2. Profil Klien .NET Framework 4.
  3. Gambar PNG ditambahkan sebagai sumber daya pada properti proyek.
  4. File baru di folder Resources dibuat secara otomatis.
  5. Buat aksi yang diatur ke sumber daya.

Ini bekerja untuk saya:

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

Jika Anda menggunakan Blend , untuk membuatnya lebih mudah dan tidak memiliki masalah dalam mendapatkan jalur yang benar untuk atribut Source , cukup seret dan letakkan gambar dari panel Project ke desainer.

pengguna42467
sumber
3

Ya, itu jalan yang benar. Anda dapat menggunakan gambar dalam file Sumber Daya menggunakan jalur:

<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>
Sanjay Ranavaya
sumber
-5

Berikut ini berfungsi dan gambar yang akan ditetapkan adalah sumber daya di properti:

    var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(MyProject.Properties.Resources.myImage.GetHbitmap(),
                                      IntPtr.Zero,
                                      Int32Rect.Empty,
                                      BitmapSizeOptions.FromEmptyOptions());
    MyButton.Background = new ImageBrush(bitmapSource);
img_username.Source = bitmapSource;
Raghulan Gowthaman
sumber
5
Jangan tersinggung tapi ini baunya seperti praktik yang buruk.
ShloEmi