문제

리소스에서 이미지를 로드한 다음 자르는 코드를 작성하려고 합니다.이 코드는 XAML에서 전체 또는 일부를 수행할 때 작동합니다.All-XAML에서 All-Code로 전환하여 다른 Uris를 사용하여 여러 곳에서 이를 재사용할 수 있기를 원합니다.

그러나 코드에서 동일한 작업을 수행하려고 하면 DirectoryNotFoundException이 발생합니다. 리소스에서 이미지를 로드하는 대신 갑자기 디스크에서 폴더를 찾으려고 하기 때문입니다.

  • XAML에서 BitmapImage를 로드한 다음 XAML에서 CroppedBitmap을 만들면 모든 것이 작동합니다.
  • XAML에서 BitmapImage를 로드한 다음 여기에서 CroppedBitmap을 생성하는 코드를 작성하면 모든 것이 작동합니다.
  • 코드에 BitmapImage를 로드하면 없이 여기에서 CroppedBitmap을 생성하면 모든 것이 작동합니다.
  • 하지만 코드에 BitmapImage를 로드하면 그리고 코드에서 CroppedBitmap을 생성하면 리소스 대신 파일 시스템에서 로드를 시도하고 DirectoryNotFoundException이 발생합니다.

코드 샘플은 다음과 같습니다.제가 뭔가 어리석은 짓을 하고 있다고 확신합니다. 하지만 지금까지 전체 내용을 세 번이나 살펴보았는데(실제 앱에서 한 번, 테스트 앱에서 한 번, 이 질문을 작성하는 동안 한 번) 동일한 결과를 얻었습니다. 세 번 모두 결과가 나왔습니다.

다음 코드 샘플 모두에 대해 프로젝트 내에 이미지 폴더를 만들고 속성이 기본값으로 설정된 "elf.png"라는 기존 이미지를 추가했습니다(Build Action = "Resource";출력 디렉터리에 복사 = "복사 안 함").


사례 1:XAML의 BitmapImage와 CroppedBitmap 둘 다.

<Window x:Class="WpfApplication8.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">
    <Window.Resources>
        <BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
        <CroppedBitmap x:Key="croppedImage" Source="{StaticResource fullImage}"
                       SourceRect="0 0 240 320"/>
    </Window.Resources>
    <Image Source="{StaticResource croppedImage}"/>
</Window>

예상대로 비트맵의 잘린 부분이 표시됩니다.


사례 2:XAML의 BitmapImage;코드 숨김의 CroppedBitmap.

XAML:

<Window x:Class="WpfApplication8.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">
    <Window.Resources>
        <BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
    </Window.Resources>
    <Image Name="image"/>
</Window>

코드 숨김의 생성자:

public Window1()
{
    InitializeComponent();
    var fullImage = (BitmapImage) FindResource("fullImage");
    var croppedImage =
        new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
    image.Source = croppedImage;
}

예상대로 비트맵의 잘린 부분도 표시됩니다.


사례 3:코드의 BitmapImage;CroppedBitmap이 없습니다.

public Window1()
{
    InitializeComponent();
    var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
    var fullImage = new BitmapImage(uri);
    image.Source = fullImage;
}

전체 비트맵이 표시됩니다.이것은 내가 원하는 것은 아니지만 올바른 종류의 Uri를 만들고 리소스에서 BitmapImage를 로드하기 위해 C# 코드를 작성하는 방법을 알고 있음을 알려줍니다.


사례 4:코드의 BitmapImage 및 CroppedBitmap.

    public Window1()
    {
        InitializeComponent();
        var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
        var fullImage = new BitmapImage(uri);
        var croppedImage =
            new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
        image.Source = croppedImage;
    }

내가 알 수 있는 한, 이것은 이전과 동일한 조각을 모아놓은 것뿐입니다.리소스에서 BitmapImage를 로드하는 코드와 로드된 BitmapImage에서 섹션을 자르는 코드를 사용합니다.그러나 어떻게든 둘을 합치면 리소스가 있다는 사실을 잊어버리고 디스크에서 로드를 시도합니다.다음 예외가 발생합니다.

  • XamlParse예외:"'WpfApplication8, 버전=1.0.0.0, Culture=neutral, PublicKeyToken=null' 어셈블리에 정의된 'Window1'의 인스턴스를 만들 수 없습니다.호출 대상에서 예외가 발생했습니다.마크업 파일 'Window1.xaml' 라인 1 위치 13에 오류가 있습니다."
    • 내부 예외: TargetInvocation예외:"호출 대상에서 예외가 발생했습니다."
      • 내부 예외: DirectoryNotFound예외:"'C:\svn\WpfApplication8\WpfApplication8\bin\Debug\Images\elf.png' 경로의 일부를 찾을 수 없습니다."

내부-내부 예외 스택 추적은 원래 예외(DirectoryNotFoundException)가 CroppedBitmap을 인스턴스화하는 줄에 의해 발생하고 있음을 보여줍니다.해당 줄이 디스크에서 읽으려고 시도하는 이유가 무엇인지, 또는 내가 말할 수 있는 만큼 동등한 XAML이 제대로 작동하는데 왜 작동하지 않는지 모르겠습니다.

XAML이 매개 변수 없는 생성자를 사용하고 있다는 것을 알고 있으므로 XAML이 실제로 수행하는 작업에 훨씬 더 가까운 다음 버전도 시도했습니다.

public Window1()
{
    InitializeComponent();
    var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
    var fullImage = new BitmapImage();
    fullImage.BeginInit();
    fullImage.UriSource = uri;
    fullImage.EndInit();
    var croppedImage = new CroppedBitmap();
    croppedImage.BeginInit();
    croppedImage.Source = fullImage;
    croppedImage.SourceRect = new Int32Rect(0, 0, 240, 320);
    croppedImage.EndInit();
    image.Source = croppedImage;
}

같은 예외입니다. 이번에는 croppedImage.EndInit(); 선.

리소스를 올바르게 로드하고 이미지를 자르기 위해 전체 코드 버전을 얻는 방법에 대한 아이디어가 있습니까?다른 XAML 버전에서는 무슨 일이 일어나고 있나요?

도움이 되었습니까?

해결책

마법은 BitmapImage에 있는 것으로 밝혀졌습니다. BaseUri 재산.BaseUri는 분명히 UriSource와 관련된 "현재 디렉터리" 역할을 합니다.

내 BitmapImage가 XAML에서 로드될 때 BaseUri는 마법처럼 "pack://application:,,,/WpfApplication8;comComponent/window1.xaml"로 설정되었습니다.CroppedBitmap을 생성하기 전에 fullImage.BaseUri를 명시적으로 동일한 값으로 설정하기 위해 코드 조각 #4를 수정했을 때 모든 것이 작동했습니다.

XAML에서 작동한 이유 (그리고 Just-BitmapImage-without-CroppedBitmap에서)

그렇다면 이 마법의 BaseUri 값은 어디서 왔을까요?

BaseUri는 IUriContext 상호 작용.IUriContext.BaseUri는 WPF 어셈블리의 두 위치에 설정되어 있으며 다양한 예제 사이에서 둘 다 그들의.내가 혼란스러웠던 것도 당연하다.

  • BamlRecordReader.ElementInitialize. BAML 로더는 IUriContext를 구현하는 요소를 로드할 때마다 BaseUri를 자동으로 설정합니다.이것은 내 예제 #1과 #2가 작동한 이유를 설명합니다.컴파일된 BAML 리소스에서 로드 중이었습니다.
  • Image.UpdateBaseUri (Source 속성이 변경될 때마다 호출됨)이는 소스가 IUriContext를 구현하는지 확인하고, 그렇다면 해당 BaseUri를 설정합니다.이것은 내 예제 #3이 작동한 이유를 설명합니다.BitmapImage를 GUI로 푸시하면 올바른 검색 경로를 얻을 수 있습니다.

BaseUri가 매직 팩:// URI로 설정된 경우에만 EXE 리소스에서 이미지를 찾습니다.그렇지 않으면(모든 것이 코드로 생성되고 GUI로 푸시되지 않는 경우와 같이) 디스크에서만 보입니다.

수정 사항

위에서 언급한 것처럼 BaseUri를 하드 코딩할 수 있습니다.하지만 BaseUriHelper 클래스는 더 나은 수정을 제공합니다.

fullImage.BaseUri = BaseUriHelper.GetBaseUri(this);

이는 fullImage가 창과 동일한 BaseUri를 갖도록 설정합니다(this).CroppedBitmap을 만들기 전에 이 작업을 수행하면 모든 것이 작동합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top