WPF에서의 이미지 동적 로드
WPF에 이상한 문제가 있어 실행 시 디스크에서 이미지를 로드하여 StackView컨테이너에 추가하고 있었습니다.그러나 이미지는 표시되지 않았습니다.몇 가지 디버깅을 한 후 방법을 찾아냈지만, 정말 말이 안 돼요.문제를 파악하기 위해 작은 데모 앱을 만들었습니다.
새 WPF 프로젝트를 만들고 다음과 같이 코드를 붙여넣습니다.
xaml:
<Window x:Class="wpfBug.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
<StackPanel Name="sp">
</StackPanel>
</Window>
xaml.cs, 기본 사용법 아래에 붙여넣기:
namespace wpfBug
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Image i = new Image();
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.EndInit();
i.Source = src;
i.Stretch = Stretch.Uniform;
//int q = src.PixelHeight; // Image loads here
sp.Children.Add(i);
}
}
}
이미지를 bin/debug 폴더에 복사하여 'picture.jpg'라고 부릅니다.
코멘트된 행에 코멘트가 없는 한, 이 프로그램은 아무것도 표시하지 않습니다.
내가 뭘 잘못했는지, 왜 이런 일이 일어나는지 설명해줄 사람?이미지를 제거하고 프로그램을 실행하면 'int q= ...' 줄에 예외가 생성됩니다.이 행에 코멘트가 붙어 있는 경우는, 이미지가 없는 경우에서도 예외 없이 프로그램이 실행됩니다.이미지를 로드하는 것은 중요한 경우에만 가능하지만 이미지 컨트롤을 스택 패널에 추가할 때 이미지를 로드해야 합니다.
아이디 있어요?
편집: 그런데 이미지를 리소스로 추가하면 'int q = ..' 행이 필요하지 않습니다.
창조가 지연되었기 때문입니다.이미지를 즉시 로드하려면 이 코드를 초기화 단계에 추가하면 됩니다.
src.CacheOption = BitmapCacheOption.온로드
다음과 같습니다.
src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
이미지 'Freq.png'이 "아이콘" 폴더에 있고 "리소스"로 정의되어 있는 실행 어셈블리에 리소스를 로드하기 위한 코드입니다.
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));
}
사용방법:
this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png");
이것은 이상한 동작으로, 왜 이런 일이 일어나는지는 말할 수 없지만, 몇 가지 옵션을 추천할 수 있습니다.
첫째, 관찰입니다.이미지를 VS에 콘텐츠로 포함시키고 출력 디렉토리에 복사하면 코드가 작동합니다.VS에서 없음으로 표시된 이미지를 복사하면 작동하지 않습니다.
해결책 1: FileStream
BitmapImage 개체는 UriSource 또는 StreamSource를 매개 변수로 받아들입니다.대신 Stream Source를 사용합시다.
FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read);
Image i = new Image();
BitmapImage src = new BitmapImage();
src.BeginInit();
src.StreamSource = stream;
src.EndInit();
i.Source = src;
i.Stretch = Stretch.Uniform;
panel.Children.Add(i);
문제는 스트림이 열린 채로 유지된다는 것입니다.이 메서드의 마지막에 닫으면 이미지가 표시되지 않습니다.이것은, 파일이 시스템에 기입 잠긴 채로 있는 것을 의미합니다.
해결책 2: Memory
이것은 기본적으로 솔루션1이지만 파일을 메모리스트림으로 읽어내고 그 메모리스트림을 인수로 전달합니다.
MemoryStream ms = new MemoryStream();
FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read);
ms.SetLength(stream.Length);
stream.Read(ms.GetBuffer(), 0, (int)stream.Length);
ms.Flush();
stream.Close();
Image i = new Image();
BitmapImage src = new BitmapImage();
src.BeginInit();
src.StreamSource = ms;
src.EndInit();
i.Source = src;
i.Stretch = Stretch.Uniform;
panel.Children.Add(i);
이것으로, 필요한 경우는, 시스템의 파일을 변경할 수 있습니다.
BitmapImage의 다양한 이벤트에 핸들러를 연결할 수 있습니다.
이미지에 관한 한 무슨 일이 일어나고 있는지 조금 알려줄 수 있습니다.
URI 에서 이미지를 로드하는 확장 방법을 다음에 나타냅니다.
public static BitmapImage GetBitmapImage(
this Uri imageAbsolutePath,
BitmapCacheOption bitmapCacheOption = BitmapCacheOption.Default)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.CacheOption = bitmapCacheOption;
image.UriSource = imageAbsolutePath;
image.EndInit();
return image;
}
사용 예:
Uri _imageUri = new Uri(imageAbsolutePath);
ImageXamlElement.Source = _imageUri.GetBitmapImage(BitmapCacheOption.OnLoad);
그렇게 간단해!
언급URL : https://stackoverflow.com/questions/569561/dynamic-loading-of-images-in-wpf
'source' 카테고리의 다른 글
데이터 테이블 열 이름을 변경하는 방법 (0) | 2023.04.26 |
---|---|
ObjectDataProvider를 통해 ComboBox를 일반 사전에 바인딩하는 방법 (0) | 2023.04.26 |
C#에서 String이 값 유형처럼 동작하는 참조 유형인 이유는 무엇입니까? (0) | 2023.04.21 |
URIFormatException: 잘못된 URI: 잘못된 포트가 지정됨 (0) | 2023.04.21 |
Windows Azure 서비스를 빌드할 때 경로가 너무 깁니다. (0) | 2023.04.21 |