source

WPF에서의 이미지 동적 로드

manycodes 2023. 4. 21. 21:05
반응형

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

반응형