Tài nguyên hình ảnh WPF


408

Tôi đến từ một trang web chủ yếu và một chút nền Windows Forms. Đối với một dự án mới, chúng tôi sẽ sử dụng WPF. Ứng dụng WPF sẽ cần 10 - 20 biểu tượng và hình ảnh nhỏ cho mục đích minh họa. Tôi đang suy nghĩ về việc lưu trữ những thứ này trong hội đồng dưới dạng tài nguyên nhúng. Đó có phải là con đường đúng đắn?

Làm cách nào để chỉ định trong XAML rằng điều khiển hình ảnh sẽ tải hình ảnh từ tài nguyên được nhúng?

Câu trả lời:


473

Nếu bạn sẽ sử dụng hình ảnh ở nhiều nơi, thì chỉ nên tải dữ liệu hình ảnh một lần vào bộ nhớ và sau đó chia sẻ nó giữa tất cả Image yếu tố.

Để làm điều này, hãy tạo BitmapSource một tài nguyên ở đâu đó:

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

Sau đó, trong mã của bạn, sử dụng một cái gì đó như:

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

Trong trường hợp của tôi, tôi thấy rằng tôi phải đặt Image.pngtệp để có hành động xây dựng Resourcethay vì chỉ Content. Điều này làm cho hình ảnh được thực hiện trong hội đồng biên dịch của bạn.


6
Nó sẽ có thể làm điều này năng động? Nếu tôi có số lượng hình ảnh khác nhau mà tôi muốn tải khi khởi động, tôi có thể tạo BitmapSource cho mỗi hình ảnh và tham khảo chúng theo cách tương tự như trên không?
Becky Franklin

2
@Becky - Có, bạn có thể, mặc dù nếu bạn muốn tham khảo chúng trong Xaml thì bạn có thể cần phải sử dụng DynamicResourcetiện ích mở rộng đánh dấu thay vì StaticResource, giả sử bạn sẽ biết các phím khi biên dịch. Trong WPF, bạn có thể tạo từ điển tài nguyên khi chạy. Trên thực tế, đó là những gì xảy ra khi bạn tải tài liệu Xaml, chỉ là bạn không thấy C # tương đương.
vẽ Noakes

9
Một cái gì đó tôi nhấn: nếu bạn thêm tài nguyên hình ảnh của mình vào một từ điển tài nguyên, đừng quên tham khảo từ điển hình ảnh đó trong XAML cho thành phần của bạn. Một cái gì đó như: <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source = "Dictionary1.xaml" /> </ResourceDictionary.MergedDictionaries> </ ResourceDictionary> </UserControl.Resources>
Dan Mitchell

4
Tôi thường thêm Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" vào Image, vì nếu không, tôi thường thấy hình ảnh được thu nhỏ một cách kỳ lạ vì một số lý do (chẳng hạn như các biểu tượng 16x16 được kéo dài thành một cái gì đó trông giống như 200x200 pixel).
HOẶC Mapper

5
Tôi thấy rằng nếu BitmapImage được khai báo trong nguồn tài nguyên tham khảo của hội đồng tham chiếu, UriSource cần phải là một packURI để điều này hoạt động. Nếu không, bạn sẽ thấy rằng bạn có thể thấy hình ảnh trong trình soạn thảo xaml của mình trong VS nhưng không có hình ảnh khi gỡ lỗi. Gói URIS: msdn.microsoft.com/en-au/l
Library / aa970069 (v = vs.100) .aspx

174

Tôi thấy rằng cách tốt nhất để sử dụng hình ảnh, video, v.v. là:

  • Thay đổi tệp của bạn "Xây dựng hành động" thành "Nội dung" . Hãy chắc chắn kiểm tra Copy để xây dựng thư mục .
    • Tìm thấy trên menu "Nhấp chuột phải" trong cửa sổ Solution Explorer.
  • Nguồn hình ảnh theo định dạng sau:
    • "/ « YourAssuggingName » ; thành phần /« YourPath »/ « YourImage.png » "

Thí dụ

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

Những lợi ích:

  • Các tập tin không được nhúng vào lắp ráp.
    • Trình quản lý tài nguyên sẽ đưa ra một số vấn đề tràn bộ nhớ với quá nhiều tài nguyên (tại thời điểm xây dựng).
  • Có thể được gọi giữa các hội đồng.

36
Cách tiếp cận tương tự này hoạt động nếu bạn nhúng tài nguyên vào cụm, nhưng bạn phải đặt "Xây dựng hành động" thành "Tài nguyên".
Ashley Davis

5
Công trình, cảm ơn. Một lưu ý cho người khác: "thành phần" là bắt buộc "như hiện tại", "Hình ảnh" là một đường dẫn tương đối của png trong dự án. Tức là hình ảnh được đặt trong thư mục gốc sẽ là "<Nguồn hình ảnh =" / WPFApplication; thành phần / Start.png "/>"
Badiboy

3
Một ví dụ về cách làm điều này trong C # sẽ rất hay. (Đó không phải là một URI hợp lệ nên không thể sử dụng nó khi xây dựng BitmapImage.)
Vaccano

5
Vì vậy, làm thế nào để bạn làm điều đó nếu tập tin được đặt thành Tài nguyên nhúng? Điều này dường như không hoạt động. Và tôi không muốn đưa hình ảnh vào dự án của mình hai lần. (Tôi đã sử dụng nó làm tài nguyên nhúng.)
BrainSlugs83

2
"Thành phần" đi vào đâu và như thế nào. Đó là một phần của một số đặc điểm kỹ thuật?
Triynko

46

Một số người đang hỏi về việc làm điều này trong mã và không nhận được câu trả lời.

Sau khi dành nhiều giờ tìm kiếm tôi đã tìm thấy một phương pháp rất đơn giản, tôi không tìm thấy ví dụ nào và vì vậy tôi chia sẻ của tôi ở đây hoạt động với hình ảnh. (của tôi là một .gif)

Tóm lược:

Nó trả về BitmapFrame mà "đích" của ImageSource có vẻ thích.

Sử dụng:

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

Phương pháp:

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

Học hỏi:

Theo kinh nghiệm của tôi, chuỗi gói không phải là vấn đề, hãy kiểm tra luồng của bạn và đặc biệt nếu đọc nó lần đầu tiên đã đặt con trỏ về cuối tệp và bạn cần đặt lại về 0 trước khi đọc lại.

Tôi hy vọng điều này sẽ giúp bạn tiết kiệm được nhiều giờ tôi ước tác phẩm này đã dành cho tôi!


44

Trong mã để tải một tài nguyên trong cụm thực thi trong đó hình ảnh của tôi Freq.pngnằm trong thư mục Iconsvà được định nghĩa là Resource:

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

Tôi cũng đã thực hiện một chức năng:

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

Cách sử dụng (giả định bạn đặt hàm trong lớp ResourceHelper):

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

Lưu ý : xem URI gói MSDN trong WPF :
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml


Uri mới ném URI không hợp lệ: Cổng không hợp lệ được chỉ định.
Steve

Bạn có uri vi phạm?
Eric Ouellet

1
giống như uri của bạn ngoại trừ cái của tôi đang chạy bên trong một WPF được lưu trữ winform. Và lược đồ "pack" chưa được đăng ký khi tôi gọi Uri mới.
Steve

1
Rất tiếc ... có lẽ nó đã được giữ lại để winform lưu trữ WPF. Tôi xin lỗi. Tôi sẽ không cố gắng sửa nó vì tôi nghĩ nó không phải là cách sử dụng phổ biến. Chúc may mắn!
Eric Ouellet

Trong trường hợp của tôi, sử dụng new Uri(@"pack://application:,,,/" + pathInApplication)cũng đã lừa
Adam Calvet Bohl

40

Vâng, đó là cách đúng đắn.

Bạn có thể sử dụng hình ảnh trong tệp tài nguyên chỉ bằng cách sử dụng đường dẫn:

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

Bạn phải đặt hành động xây dựng của tệp hình ảnh thành "Tài nguyên".


1
Cám ơn vì cái này. Có cách nào để làm một cái gì đó tương tự với ImageSource, về cơ bản là tải hình ảnh một lần vào từ điển tài nguyên. Tôi sợ rằng phương pháp này tải dữ liệu hình ảnh nhiều lần trong bộ nhớ.
Drew Noakes

2
Đây sẽ là một mớ hỗn độn khi bạn cần cấu trúc lại mã của mình. Bạn sẽ phải thay đổi thủ công tất cả các tham chiếu hình ảnh nếu tài liệu xaml của bạn xảy ra để thay đổi không gian tên. Phương pháp được mô tả bởi Drew Noakes mượt mà và dễ bảo trì hơn rất nhiều.
Kasper Holdum

14

Mô tả đầy đủ cách sử dụng tài nguyên: Tệp tài nguyên, nội dung và dữ liệu ứng dụng WPF

Và cách tham chiếu chúng, hãy đọc "Gói URI trong WPF".

Nói tóm lại, thậm chí còn có phương tiện để tham chiếu tài nguyên từ các hội đồng tham chiếu / tham chiếu.


Liên kết dường như là trực tiếp và tốt (mặc dù nó nói "Tài liệu này được lưu trữ và không được duy trì." ).
Peter Mortensen

5
  1. Visual Studio 2010 Professional SP1.
  2. Hồ sơ khách hàng .NET Framework 4.
  3. Hình ảnh PNG được thêm dưới dạng tài nguyên trên các thuộc tính dự án.
  4. Tập tin mới trong thư mục Tài nguyên được tạo tự động.
  5. Xây dựng hành động được đặt thành tài nguyên.

Điều này làm việc cho tôi:

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

3

Nếu bạn đang sử dụng Blend , để làm cho nó dễ dàng hơn và không gặp khó khăn gì trong việc tìm đường dẫn chính xác cho thuộc tính Nguồn , chỉ cần kéo và thả hình ảnh từ bảng Project vào trình thiết kế.


3

Vâng, đó là cách đúng đắn. Bạn có thể sử dụng hình ảnh trong tệp Tài nguyên bằng đường dẫn:

<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

Sau đây làm việc và hình ảnh được thiết lập là tài nguyên trong các thuộc tính:

    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
Không có hành vi phạm tội nhưng điều này có mùi như thực hành xấu.
ShloEmi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.