Đặt nguồn hình ảnh WPF trong mã


325

Tôi đang cố gắng đặt mã nguồn của hình ảnh WPF. Hình ảnh được nhúng như một tài nguyên trong dự án. Bằng cách xem các ví dụ tôi đã đưa ra đoạn mã dưới đây. Vì một số lý do, nó không hoạt động - hình ảnh không hiển thị.

Bằng cách gỡ lỗi tôi có thể thấy rằng luồng chứa dữ liệu hình ảnh. Vì vậy những gì là sai?

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;

Biểu tượng được định nghĩa giống như thế này: <Image x:Name="_icon" Width="16" Height="16" />


Nếu hình ảnh nằm trên một ổ đĩa cục bộ, <Image Source="some_fully_qualified_path">trong XAML không bao giờ bị lỗi.
Laurie Stearn

@Laurie Tìm hiểu toàn bộ vấn đề là chúng tôi không biết đường dẫn và cần mã để xác định nó. Là một người mới biết đến lập trình GUI Windows, tôi phải thừa nhận rằng WinForms có vẻ hấp dẫn hơn so với crap XAML này.
Alex Jansen

Câu trả lời:


415

Sau khi gặp vấn đề tương tự như bạn và đọc một số bài, tôi phát hiện ra giải pháp - Gói URI .

Tôi đã làm như sau trong mã:

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;

Hoặc ngắn hơn, bằng cách sử dụng một hàm tạo BitmapImage khác:

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

URI được chia thành các phần:

  • Thẩm quyền: application:///
  • Đường dẫn: Tên của tệp tài nguyên được biên dịch thành một cụm tham chiếu. Đường dẫn phải tuân theo định dạng sau:AssemblyShortName[;Version][;PublicKey];component/Path

    • HộiShortName: tên viết tắt của hội đồng tham chiếu.
    • ; Phiên bản [tùy chọn]: phiên bản của tham chiếu có chứa tệp tài nguyên. Điều này được sử dụng khi hai hoặc nhiều hội đồng tham chiếu có cùng tên ngắn được tải.
    • ; PublicKey [tùy chọn]: khóa chung được sử dụng để ký hợp đồng tham chiếu. Điều này được sử dụng khi hai hoặc nhiều hội đồng tham chiếu có cùng tên ngắn được tải.
    • ; thành phần: xác định rằng lắp ráp được tham chiếu được tham chiếu từ lắp ráp cục bộ.
    • / Đường dẫn: tên của tệp tài nguyên, bao gồm đường dẫn của nó, liên quan đến thư mục gốc của thư mục dự án của tổ hợp được tham chiếu.

Ba dấu gạch chéo sau application:phải được thay thế bằng dấu phẩy:

Lưu ý: Thành phần quyền hạn của URI gói là một URI được nhúng trỏ đến gói và phải tuân theo RFC 2396. Ngoài ra, ký tự "/" phải được thay thế bằng ký tự "," và các ký tự dành riêng như "%" và "?" phải được trốn thoát. Xem OPC để biết chi tiết.

Và tất nhiên, hãy đảm bảo bạn đặt hành động xây dựng trên hình ảnh của mình thành Resource.


Vâng, đây là giải pháp tôi tìm thấy chính mình sau một số thử nghiệm và lỗi. Cảm ơn đã giải thích cặn kẽ. Trả lời chấp nhận!
Torbjørn

Tôi không biết tại sao điều này lại cần thiết và tại sao những câu trả lời khác không hiệu quả với tôi ...
Torbjørn

những câu trả lời khác trong câu hỏi này và những câu hỏi khác cũng không có tác dụng với tôi. Điều này hoạt động hoàn hảo. Cảm ơn.
Thomas Stock

9
Được rồi, nhưng không có một số phương thức hoặc lớp mà trình phân tích cú pháp XAML sử dụng để chuyển đổi chuỗi đường dẫn đơn giản thành ImageSource? Chúng ta không thể sử dụng nó?
Qwertie

1
Tôi thường thấy đoạn trích này được sao chép vào các bài đăng khác, nơi mọi người thường bỏ qua sự tồn tại của hàm BitmapImage(Uri)tạo, điều này giúp tránh sự cần thiết phải gọi BeginInit và EndInit. Tôi đã thêm nó ở đây.
Clemens

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

Điều này sẽ tải một hình ảnh gọi là "Untitle.png" trong một thư mục có tên "Hình ảnh" với "Hành động xây dựng" được đặt thành "Tài nguyên" trong một cụm có tên "WpfApplication1".


16
Cảm ơn vì điều đó. Một vấn đề khiến tôi gặp rắc rối với wpf, hình ảnh phải được đánh dấu là tài nguyên để làm việc này.
si618

4
Giải pháp này đã cho tôi một ngoại lệ vì vậy tôi đã thử giải pháp của Jared Harley và nó đã hoạt động ...
Sangram Nandkhile

2
điều quan trọng nhất là "UriKind.RelativeOrAbsolute" - những ví dụ khác luôn đưa ra ngoại lệ
Sven

9
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);sẽ là đủ
Hamzeh Soboh

... Và dễ dàng hơn nhiều. Cảm ơn Hamzeh
pStan 4/2/2015

74

Đây là một mã ít hơn một chút và có thể được thực hiện trong một dòng duy nhất.

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

8
Đây chắc chắn là câu trả lời tốt nhất, sử dụng triển khai riêng của
.NET

Điều gì xảy ra nếu chúng ta cần thiết lập chiều cao và chiều rộng của hình ảnh tức là icon.png? Bởi vì bằng cách sử dụng _image.height và _image. Thong, nó đặt cửa sổ hình ảnh không phải là hình ảnh thực tế tức là icon.png.
Secretgenes

41

Rất dễ:

Để thiết lập hình ảnh của một mục menu một cách linh hoạt, chỉ làm như sau:

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

... Trong khi "icon.ico" có thể được đặt ở mọi nơi (hiện tại nó nằm trong thư mục 'Tài nguyên') và phải được liên kết dưới dạng Tài nguyên ...


2
Ngắn hơn = tốt hơn. Tôi đã phải đặt nó là @ "/ thư mục / image.png" nhưng sau đó nó hoạt động tốt. Cảm ơn!
gjvdkamp

3
Khi tôi chỉ định nguồn hình ảnh, nó chỉ hiển thị trống :(
HaloMediaz

Đường dẫn @HaloMediaz có thể sai .... ví dụ: bạn có Tài nguyên nhưng bạn có thể viết Tài nguyên
Rouzbeh Zarandi

Điều này làm việc cho tôi và đơn giản hơn nhiều so với các URI tuyệt đối trong các câu trả lời khác.
Psiloc

16

Bạn cũng có thể giảm điều này xuống một dòng. Đây là mã tôi đã sử dụng để đặt Biểu tượng cho cửa sổ chính của mình. Nó giả sử tệp .ico được đánh dấu là Nội dung và đang được sao chép vào thư mục đầu ra.

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

16

Cách đơn giản nhất:

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

15

Bạn đã thử chưa:

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

Đây là cách của tôi:

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

Sử dụng:

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

8

Dưới đây là một ví dụ thiết lập đường dẫn hình ảnh một cách linh hoạt (hình ảnh nằm ở đâu đó trên đĩa thay vì xây dựng dưới dạng tài nguyên):

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

Phản ánh về các biểu tượng ...

Suy nghĩ đầu tiên, bạn sẽ nghĩ rằng thuộc tính Icon chỉ có thể chứa một hình ảnh. Nhưng nó thực sự có thể chứa bất cứ thứ gì! Tôi tình cờ phát hiện ra điều này khi tôi lập trình cố gắng thiết lậpImage tính trực tiếp thành một chuỗi có đường dẫn đến hình ảnh. Kết quả là nó không hiển thị hình ảnh, mà là văn bản thực tế của đường dẫn!

Điều này dẫn đến một giải pháp thay thế là không phải tạo hình ảnh cho biểu tượng mà thay vào đó sử dụng văn bản có phông chữ biểu tượng để hiển thị một "biểu tượng" đơn giản. Ví dụ sau sử dụng phông chữ Wingdings có chứa biểu tượng "floppydisk". Biểu tượng này thực sự là ký tự <, có ý nghĩa đặc biệt trong XAML, vì vậy chúng tôi phải sử dụng phiên bản được mã hóa &lt;thay thế. Điều này hoạt động như một giấc mơ! Phần sau đây hiển thị biểu tượng floppydisk dưới dạng biểu tượng trên mục menu:

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

Câu hỏi: " Hình ảnh được nhúng dưới dạng tài nguyên trong dự án ", trả lời: " Đây là một ví dụ [cho hình ảnh] nằm ở đâu đó trên đĩa thay vì xây dựng dưới dạng tài nguyên ".
phút

7

Nếu hình ảnh của bạn được lưu trữ trong ResourceDipedia, bạn có thể làm điều đó chỉ với một dòng mã:

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

6

Cũng có một cách đơn giản hơn. Nếu hình ảnh được tải dưới dạng tài nguyên trong XAML và mã được đề cập là mã phía sau cho nội dung XAML đó:

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

4

Đặt khung trong VisualBrush:

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

brush.Visual = frame;

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

Đặt VisualBrush trong 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;

Bây giờ, đặt GeometryDrawing trong Bản vẽ:

new DrawingImage(drawing);

Đặt cái này vào nguồn hình ảnh của bạn, và voilà!

Bạn có thể làm điều đó dễ dàng hơn nhiều mặc dù:

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

Và trong mã:

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

CƯỜI LỚN! Tại sao làm cho nó dễ dàng khi bạn lần đầu tiên có thể gây khó khăn :) Tôi sẽ thử giải pháp đơn giản của bạn trước khi tôi chấp nhận mặc dù ...
Torbjørn

Thật ra điều này chẳng giúp ích gì cho tôi cả. Có lẽ tôi ngu ngốc :( Đừng có thời gian để xem xét kỹ hơn ngay bây giờ (dự án thú cưng). Tôi muốn có nhiều câu trả lời hơn khi tôi quay lại với nó :)
Torbjørn

3

Cũng có một cách đơn giản hơn. Nếu hình ảnh được tải dưới dạng tài nguyên trong XAML và mã được đề cập là cơ sở mã cho XAML đó:

Đây là từ điển tài nguyên cho tệp XAML - dòng duy nhất bạn quan tâm là ImageBrush với khóa "PosterBrush" - phần còn lại của mã chỉ để hiển thị ngữ cảnh

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

        </ResourceDictionary>
    </UserControl.Resources>

Bây giờ, trong mã phía sau, bạn có thể làm điều này

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

2

Cách tải hình ảnh từ được nhúng trong các biểu tượng tài nguyên và hình ảnh (phiên bản đã sửa của Arcturus):

Giả sử bạn muốn thêm một nút có hình ảnh. Những gì bạn nên làm?

  1. Thêm vào biểu tượng thư mục dự án và đặt hình ảnh ClickMe.png tại đây
  2. Trong thuộc tính của 'ClickMe.png', đặt 'BuildAction' thành 'Tài nguyên'
  3. Giả sử tên lắp ráp đã biên dịch của bạn là 'Company. ProducttAssugging.dll'.
  4. Bây giờ là lúc tải hình ảnh của chúng tôi trong 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>

Làm xong.


2

Tôi là người mới sử dụng WPF, nhưng không có trong .NET.

Tôi đã dành năm giờ để cố gắng thêm tệp PNG vào "Dự án thư viện điều khiển tùy chỉnh WPF" trong .NET 3.5 (Visual Studio 2010) và đặt nó làm nền của điều khiển được kế thừa hình ảnh.

Không có gì liên quan với URI làm việc. Tôi không thể tưởng tượng được tại sao không có phương pháp nào để lấy URI từ tệp tài nguyên, thông qua IntelliSense, có thể là:

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

Tôi đã thử rất nhiều URI và chơi với ResourceManager và các phương thức GetManifest của hội, nhưng tất cả đều có ngoại lệ hoặc giá trị NULL.

Ở đây tôi lấy mã làm việc cho tôi:

// 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
Tôi nghĩ vấn đề là WPF không "thích" cách tiếp cận truyền thống là đưa tài nguyên vào các tệp resx. Thay vào đó, bạn phải thêm hình ảnh trực tiếp vào dự án của mình và đặt thuộc tính Build Action của nó thành Resource. Tôi không biết sự khác biệt là gì (theo định dạng tệp vật lý) giữa hai cách tiếp cận.
Qwertie

1
Đảm bảo hành động xây dựng là nội dung
Jerry Nixon

1

Nếu bạn đã có một luồng và biết định dạng, bạn có thể sử dụng một cái gì đó như thế này:

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

1

Bạn chỉ cần bỏ lỡ một chút.

Để có được tài nguyên nhúng từ bất kỳ hội đồng nào, bạn phải đề cập đến tên tập hợp với tên tệp của bạn như tôi đã đề cập ở đây:

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 () dường như không tồn tại trong WPF.
Myosotis

Nó có sẵn kiểm tra bên dưới liên kết msdn.microsoft.com/en-us/l
Library / từ
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.