ทรัพยากรอิมเมจ WPF


408

ฉันมาจากเว็บส่วนใหญ่และพื้นหลังแบบฟอร์ม Windows เล็กน้อย สำหรับโครงการใหม่เราจะใช้ 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 ต่อภาพและอ้างอิงกับพวกเขาในลักษณะเดียวกับข้างต้นหรือไม่
Becky Franklin

2
@Becky - ใช่คุณทำได้ แต่ถ้าคุณต้องการอ้างถึงพวกเขาใน Xaml คุณอาจต้องใช้DynamicResourceส่วนขยายมาร์กอัปแทนStaticResourceโดยสมมติว่าคุณจะรู้คีย์ในเวลารวบรวม ใน WPF คุณสามารถสร้างพจนานุกรมทรัพยากรได้ที่รันไทม์ ในความเป็นจริงนั่นคือสิ่งที่เกิดขึ้นเมื่อคุณโหลดเอกสาร Xaml เป็นเพียงว่าคุณไม่เห็น C # ที่เทียบเท่ากัน
Drew Noakes

9
สิ่งที่ฉันได้รับ: ถ้าคุณเพิ่มทรัพยากรรูปภาพลงในพจนานุกรมทรัพยากรอย่าลืมอ้างอิงพจนานุกรมรูปภาพนั้นใน XAML สำหรับส่วนประกอบของคุณ สิ่งที่ชอบ: <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source = "Dictionary1.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </UserControl.Resources>
Dan Mitchell

4
ฉันมักจะเพิ่มลงWidth="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" ไปImageเพราะฉันมักจะเห็นภาพที่ได้รับการปรับขนาดอย่างผิดปกติด้วยเหตุผลบางอย่าง (เช่นไอคอน 16x16 ขยายไปถึงบางสิ่งที่ดูเหมือน 200x200 พิกเซล)
หรือผู้ทำแผนที่

5
ฉันพบว่าหาก BitmapImage ถูกประกาศใน resourcedictionary ของชุดประกอบที่อ้างถึง UriSource จะต้องมีชุดข้อมูลสำหรับการทำงานนี้ มิฉะนั้นคุณจะพบว่าคุณสามารถเห็นภาพในเครื่องมือแก้ไข xaml ของคุณใน VS แต่ไม่มีภาพเมื่อทำการดีบั๊ก แพ็คยูริ: msdn.microsoft.com/en-au/library/aa970069(v=vs.100).aspx
failedprogramming

174

ฉันพบว่าวิธีปฏิบัติที่ดีที่สุดในการใช้รูปภาพวิดีโอและอื่น ๆ คือ:

  • เปลี่ยนไฟล์ของคุณ"การกระทำรูปร่าง"เพื่อ"เนื้อหา" จะได้รับการตรวจสอบเพื่อตรวจคัดลอกไปสร้างไดเรกทอรี
    • พบได้ในเมนู "คลิกขวา" ที่หน้าต่างโซลูชัน Explorer
  • แหล่งที่มาของภาพในรูปแบบต่อไปนี้:
    • "/ « YourAssemblyName » ; component / « YourPath » / « YourImage.png » "

ตัวอย่าง

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

ประโยชน์ที่ได้รับ:

  • ไฟล์จะไม่ถูกฝังลงในแอสเซมบลี
    • ตัวจัดการทรัพยากรจะทำให้เกิดปัญหาหน่วยความจำล้นด้วยทรัพยากรมากเกินไป (ณ เวลาที่สร้าง)
  • สามารถเรียกระหว่างการประกอบ

36
วิธีการเดียวกันนี้ใช้งานได้หากคุณฝังทรัพยากรในชุดประกอบ แต่คุณต้องตั้งค่า "Build Action" เป็น "Resource"
แอชลีย์เดวิส

5
ได้ผลขอบคุณ หมายเหตุหนึ่งสำหรับผู้อื่น: "องค์ประกอบ" จำเป็นต้องใช้ "ตามที่เป็น", "รูปภาพ" เป็นเส้นทางสัมพัทธ์ของ png ในโครงการ รูปภาพ Ie ที่วางในรูทจะเป็น "<Image Source =" / WPFApplication; component / Start.png "/>"
Badiboy

3
ตัวอย่างของวิธีการทำใน C # น่าจะดี (นั่นไม่ใช่ URI ที่ถูกต้องดังนั้นจึงไม่สามารถใช้เมื่อสร้าง BitmapImage)
Vaccano

5
ดังนั้นคุณจะทำอย่างไรหากไฟล์ถูกตั้งค่าเป็นทรัพยากรที่ฝังตัว? ดูเหมือนจะใช้งานไม่ได้ และฉันไม่ต้องการรวมภาพในโครงการของฉันสองครั้ง (ฉันใช้มันเป็นทรัพยากรที่ฝังอยู่แล้ว)
BrainSlugs83

2
ส่วนประกอบ "มาจากไหนและอย่างไร เป็นส่วนหนึ่งของข้อกำหนดบางอย่างหรือไม่?
Triynko

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

หมายเหตุ : ดูMSDN Pack URIs ใน WPF :
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml


ใหม่ Uri พ่น URI ไม่ถูกต้อง: ระบุพอร์ตไม่ถูกต้อง
Steve

คุณมี uri ที่กระทำผิดหรือไม่?
Eric Ouellet

1
uri เดียวกันกับคุณยกเว้นว่าเหมืองทำงานอยู่ใน winform ที่โฮสต์ WPF และ schema "pack" ยังไม่ได้ลงทะเบียนเมื่อฉันเรียก Uri ใหม่
Steve

1
โอ๊ะโอ ... มันอาจเกี่ยวข้องกับ winform ที่โฮสต์ WPF ฉันขอโทษ. ฉันจะไม่พยายามแก้ไขเพราะฉันคิดว่ามันไม่ใช่การใช้งานทั่วไป โชคดี!
Eric Ouellet

ในกรณีของฉันการใช้new Uri(@"pack://application:,,,/" + pathInApplication)ยังทำเคล็ดลับ
Adam Calvet Bohl

40

ใช่มันเป็นวิธีที่ถูกต้อง

คุณสามารถใช้อิมเมจในไฟล์รีซอร์สโดยใช้พา ธ :

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

คุณต้องตั้งค่าการสร้างของไฟล์ภาพเป็น "ทรัพยากร"


1
ขอบคุณสำหรับสิ่งนี้. มีวิธีการทำสิ่งที่คล้ายกับ ImageSource หรือไม่โดยการโหลดภาพลงในพจนานุกรมทรัพยากร ฉันกลัวว่าวิธีการนี้จะโหลดข้อมูลภาพหลายครั้งในหน่วยความจำ
Drew Noakes

2
นี้จะเป็นระเบียบเมื่อคุณต้องการ refactor รหัสของคุณ คุณจะต้องเปลี่ยนการอ้างอิงภาพทั้งหมดด้วยตนเองหากเอกสาร xaml ของคุณเกิดขึ้นเพื่อเปลี่ยนเนมสเปซ วิธีที่อธิบายโดย Drew Noakes นั้นราบรื่นและสามารถบำรุงรักษาได้มาก
Kasper Holdum

14

คำอธิบายโดยละเอียดเกี่ยวกับวิธีใช้ทรัพยากร: WPF Application Resource, Content และ Data Files

และวิธีอ้างอิงพวกเขาอ่าน "Pack URIs ใน WPF"

ในระยะสั้นยังมีวิธีการอ้างอิงทรัพยากรจากแอสเซมบลีอ้างอิง / อ้างอิง


ดูเหมือนว่าลิงก์นี้จะใช้งานได้ดี (แม้ว่าจะมีข้อความว่า"เอกสารนี้ถูกเก็บถาวรและไม่ได้รับการบำรุงรักษา" )
Peter Mortensen

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เพียงลากและวางภาพจากแผงโครงการไปยังผู้ออกแบบ


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.