코드에서 WPF 이미지 소스 설정


325

코드에서 WPF 이미지의 소스를 설정하려고합니다. 이미지는 프로젝트에서 리소스로 포함됩니다. 예제를 보면서 아래 코드를 생각해 냈습니다. 어떤 이유로 든 작동하지 않습니다-이미지가 표시되지 않습니다.

디버깅하여 스트림에 이미지 데이터가 포함되어 있음을 알 수 있습니다. 무슨 일이야?

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;

아이콘은 다음과 같이 정의됩니다. <Image x:Name="_icon" Width="16" Height="16" />


이미지가 로컬 드라이브에 있으면 <Image Source="some_fully_qualified_path">XAML에서 실패하지 않습니다.
Laurie Stearn

@LaurieStearn 요점은 우리가 경로를 알지 못하고 그것을 결정하기 위해 코드가 필요하다는 것입니다. Windows GUI 프로그래밍을 처음 접하는 사람이라면 WinForms가이 XAML 쓰레기보다 더 매력적으로 보인다는 것을 인정해야합니다.
Alex Jansen

답변:


416

당신과 같은 문제를 겪고 약간의 독서를 한 후에 솔루션 팩 URI를 발견했습니다 .

코드에서 다음을 수행했습니다.

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;

또는 다른 BitmapImage 생성자를 사용하여 더 짧게 만듭니다.

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

URI는 여러 부분으로 나뉩니다.

  • 권위: application:///
  • 경로 : 참조 된 어셈블리로 컴파일 된 리소스 파일의 이름입니다. 경로는 다음 형식을 따라야합니다.AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName : 참조 된 어셈블리의 짧은 이름입니다.
    • ; Version [선택 사항] : 리소스 파일이 포함 된 참조 된 어셈블리의 버전입니다. 짧은 이름이 동일한 둘 이상의 참조 된 어셈블리가로드 될 때 사용됩니다.
    • ; PublicKey [선택 사항] : 참조 된 어셈블리에 서명하는 데 사용 된 공개 키. 짧은 이름이 동일한 둘 이상의 참조 된 어셈블리가로드 될 때 사용됩니다.
    • ; component : 참조되는 어셈블리가 로컬 어셈블리에서 참조되도록 지정합니다.
    • / 경로 : 참조 된 어셈블리 프로젝트 폴더의 루트에 상대적인 경로를 포함한 리소스 파일의 이름.

세 개의 슬래시는 이후 application:에 쉼표로 교체해야합니다.

참고 : 팩 URI의 권한 구성 요소는 패키지를 가리키는 임베디드 URI이며 RFC 2396을 준수해야합니다. 또한 "/"문자는 ","문자 및 "%"와 같은 예약 문자로 바꿔야합니다. "?" 탈출해야합니다. 자세한 내용은 OPC를 참조하십시오.

물론 이미지의 빌드 작업을로 설정했는지 확인하십시오 Resource.


예, 이것은 시행 착오 후에 내가 찾은 해결책이었습니다. 철저한 설명에 감사드립니다. 답변이 접수되었습니다!
Torbjørn

왜 이것이 필요한지, 왜 다른 답변이 저에게 효과가 없는지 모르겠습니다 ...
Torbjørn

이 질문에 대한 다른 답변과 다른 질문도 나에게 도움이되지 않았습니다. 이것은 완벽하게 작동합니다. 감사.
Thomas 주식

9
좋아,하지만 XAML 파서가 간단한 경로 문자열을 ImageSource로 변환하는 데 사용하는 메서드 나 클래스가 없습니까? 그냥 사용할 수 없습니까?
Qwertie

1
사람들이 일반적으로 BitmapImage(Uri)생성자 의 존재를 무시하여 BeginInit 및 EndInit를 호출 할 필요가 없는 다른 게시물에이 스 니펫이 복사되는 경우가 종종 있습니다 . 여기에 추가했습니다.
Clemens

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

그러면 "WpfApplication1"이라는 어셈블리에서 "Build Action"이 "Resource"로 설정된 "Images"폴더에 "Untitled.png"라는 이미지가로드됩니다.


16
고마워 wpf의 멍청한 놈으로 나를 트립 한 한 가지 문제, 이미지가 작동하려면 리소스로 표시되어야합니다.
si618

4
이 솔루션은 저에게 예외를
주어서

2
가장 중요한 것은 "UriKind.RelativeOrAbsolute"입니다. 다른 예제는 항상 예외를 던졌습니다
Sven

9
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);충분하다
Hamzeh Soboh

... 훨씬 쉬워졌습니다. 감사합니다 Hamzeh
pStan

74

이것은 약간 적은 코드이며 한 줄로 수행 할 수 있습니다.

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

8
이것은 확실히 .NETs에게 자신의 구현 이용하는 가장 좋은 대답입니다
joshcomley

icon.png 이미지의 높이와 너비를 설정해야한다면 어떻게해야합니까? _image.height 및 _image.width를 사용하여 실제 이미지가 아닌 이미지 창을 설정합니다 (예 : icon.png).
secretgenes

41

아주 쉽게:

메뉴 항목의 이미지를 동적으로 설정하려면 다음을 수행하십시오.

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

"icon.ico"는 어디에나있을 수 있으며 (현재 'Resources'디렉토리에 위치) Resource로 링크되어야합니다.


2
짧을수록 좋습니다. 그래도 @ "/ folder / image.png"로 설정해야했지만 정상적으로 작동했습니다. 감사!
gjvdkamp

3
이미지 소스를 할당하면 이미지가 공백으로 표시됩니다. (
HaloMediaz

@HaloMediaz 경로는 .... 예를 들어 당신이 자료를 잘못 될 수도 있지만 당신은 자원을 쓸 수 있습니다
Rouzbeh Zarandi

이것은 저에게 효과적이며 다른 답변의 절대 URI보다 훨씬 간단합니다.
Psiloc

16

이것을 한 줄로 줄일 수도 있습니다. 이것은 기본 창에 아이콘을 설정하는 데 사용한 코드입니다. .ico 파일이 내용으로 표시되어 출력 디렉토리로 복사되고 있다고 가정합니다.

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

16

가장 간단한 방법 :

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

15

시도해 보셨습니까?

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

이게 내 방법이야:

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

용법:

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

8

이미지 경로를 동적으로 설정하는 예는 다음과 같습니다 (이미지는 리소스로 빌드하지 않고 디스크 어딘가에 위치).

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

아이콘에 대한 반사 ...

처음에는 Icon 속성에 이미지 만 포함될 수 있다고 생각했습니다. 그러나 실제로 무엇이든 포함 할 수 있습니다! 프로그래밍 방식으로 Image속성을 이미지 경로가있는 문자열 로 설정하려고 시도했을 때 우연히이 사실을 발견했습니다 . 결과는 이미지가 아니라 경로의 실제 텍스트입니다!

이로 인해 아이콘 이미지를 만들 필요는 없지만 간단한 "아이콘"을 표시하기 위해 기호 글꼴이있는 텍스트를 사용할 수 있습니다. 다음 예제에서는 "floppydisk"기호가 포함 된 Wingdings 글꼴 을 사용합니다 . 이 기호는 실제로 문자 <이므로 XAML에서 특별한 의미가 있으므로 &lt;대신 인코딩 된 버전을 사용해야합니다 . 이것은 꿈처럼 작동합니다! 다음은 메뉴 항목에서 플로피 디스크 기호를 아이콘으로 나타냅니다.

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

질문 : " 프로젝트에 이미지가 리소스로 포함되어 있습니다. ", 답변 : " 리소스로 빌드하기보다는 디스크 어딘가에있는 [이미지의 예]가 있습니다 .

7

이미지가 ResourceDictionary에 저장된 경우 한 줄의 코드만으로 이미지를 수행 할 수 있습니다.

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

6

더 간단한 방법도 있습니다. 이미지가 XAML에서 리소스로로드되고 해당 코드가 해당 XAML 콘텐츠의 코드 숨김 인 경우 :

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

4

VisualBrush에 프레임을 넣습니다.

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

brush.Visual = frame;

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

GeometryDrawing에 VisualBrush를 넣습니다

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;

이제 GeometryDrawing을 DrawingImage에 넣습니다.

new DrawingImage(drawing);

이것을 이미지의 소스에 올려 놓으십시오!

그래도 훨씬 쉽게 할 수 있습니다.

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

그리고 코드에서 :

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

롤! 당신이 처음에 어려울 수있는 이유는 무엇입니까? :) 비록 받아들이 기 전에 간단한 해결책을 시도 할 것입니다 ...
Torbjørn

실제로 이것은 전혀 도움이되지 않았습니다. 어쩌면 나는 바보입니다 :( 지금 더 자세히 볼 시간이 없습니다 (애완 동물 프로젝트). 다시 돌아올 때 더 많은 답변을 원하십니까 :)
Torbjørn

3

더 간단한 방법도 있습니다. 이미지가 XAML에서 리소스로로드되고 해당 코드가 해당 XAML의 코드 숨김 인 경우 :

XAML 파일에 대한 리소스 사전은 다음과 같습니다. "PosterBrush"키가있는 ImageBrush 만 있으면됩니다. 나머지 코드는 컨텍스트를 표시하기위한 것입니다.

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

        </ResourceDictionary>
    </UserControl.Resources>

이제 코드 뒤에, 당신은 이것을 할 수 있습니다

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

2

리소스 아이콘 및 이미지에 포함 된 이미지를로드하는 방법 (수정 된 버전의 Arcturus) :

이미지가있는 버튼을 추가한다고 가정합니다. 어떻게해야합니까?

  1. 프로젝트 폴더 아이콘에 추가하고 이미지를 여기에 클릭하십시오. ClickMe.png
  2. 'ClickMe.png'의 속성에서 'BuildAction'을 'Resource'로 설정하십시오.
  3. 컴파일 된 어셈블리 이름이 'Company.ProductAssembly.dll'이라고 가정하십시오.
  4. 이제 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>

끝난.


2

WPF를 처음 사용하지만 .NET에는 없습니다.

.NET 3.5 (Visual Studio 2010)의 "WPF Custom Control Library Project"에 PNG 파일을 추가하고 이미지 상속 컨트롤의 배경으로 설정하는 데 5 시간을 보냈습니다.

URI와 관련된 것은 없습니다. IntelliSense를 통해 리소스 파일에서 URI를 가져 오는 방법이없는 이유를 상상할 수 없습니다.

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

나는 많은 URI를 시도하고 ResourceManager와 Assembly의 GetManifest 메소드를 가지고 놀았지만 모두 예외 또는 NULL 값이있었습니다.

여기에 나를 위해 일한 코드가 있습니다.

// 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
문제는 WPF가 리소스를 resx 파일에 넣는 전통적인 방법을 "좋아하지"않는다는 것입니다. 대신 이미지를 프로젝트에 직접 추가하고 Build Action 속성을 Resource로 설정해야합니다. 두 방법의 차이점 (물리적 파일 형식)이 무엇인지 모르겠습니다.
Qwertie

1
빌드 액션이 만족 스러운지 확인
Jerry Nixon

1

이미 스트림이 있고 형식을 알고 있다면 다음과 같이 사용할 수 있습니다.

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

1

당신은 조금 놓쳤다.

모든 어셈블리에서 임베디드 리소스를 얻으려면 여기에서 언급 한 것처럼 파일 이름으로 어셈블리 이름을 언급해야합니다.

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 ()가 WPF에 존재하지 않는 것 같습니다.
Myosotis

아래 링크에서 확인할 수 있습니다. 링크 msdn.microsoft.com/en-us/library/…
maulik
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.