2009-06-28 5 views
2

Я пытаюсь написать код, который будет загружать изображение с ресурса, а затем обрезать его. Этот код работает, когда я делаю все или часть его в XAML. Я хочу перейти от all-XAML ко всему коду, поэтому я могу повторно использовать это более одного места, с разными Uris.Создание CroppedBitmap во время выполнения - не загружается с ресурса

Но когда я пытаюсь сделать то же самое в коде, я получаю DirectoryNotFoundException, потому что внезапно он начинает искать папку на диске, вместо того, чтобы загружать изображение с ресурса.

  • Если я загружаю BitmapImage в XAML, а затем создаю CroppedBitmap в XAML, все работает.
  • Если я загружаю BitmapImage в XAML, а затем пишу код для создания CroppedBitmap, все будет работать.
  • Если я загружаю BitmapImage в коде, без создания CroppedBitmap от него, все работает.
  • Но если я загружаю BitmapImage в код и, создайте CroppedBitmap в коде, он пытается загрузить из файловой системы вместо ресурсов, и я получаю DirectoryNotFoundException.

Образцы кода приведены ниже. Я уверен, что я делаю что-то глупое, но в три раза теперь я бежать через все это (один раз в моем реальном приложении, один раз в тестовом приложении, и один раз, когда описываю этот вопрос), и я получил то же самое результаты все три раза.

Для всех следующих примеров кода я создал папку «Изображения» внутри моего проекта и добавил существующее изображение под названием «elf.png», свойства которого установлены по умолчанию (Build Action = «Resource»; в Output Directory = «Не копировать»).


Дело 1: И битмапИмэйдж и 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"/> 
     <CroppedBitmap x:Key="croppedImage" Source="{StaticResource fullImage}" 
         SourceRect="0 0 240 320"/> 
    </Window.Resources> 
    <Image Source="{StaticResource croppedImage}"/> 
</Window> 

Это показывает обрезанную часть растрового изображения, как и ожидалось.


Дело 2: BitmapImage в XAML; 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; 
} 

Это показывает все растровое изображение. Это не то, что я хочу, но действительно говорит мне, что я знаю, как писать C# код, чтобы создать правильный вид Uri и загрузить BitmapImage из ресурса.


Дело 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. Но каким-то образом, когда они объединяются, он забывает, что ресурс есть, и пытается загрузить с диска. Я получаю следующее исключение:

  • XamlParseException:. «Не удается создать экземпляр определенного в сборке„window1“„WpfApplication8, Version = 1.0.0.0, культура = нейтральной, PublicKeyToken = нуль“Исключение было брошено мишенью вызова. Ошибка в файле разметки 'Window1.xaml' Строка 1 Позиция 13. "
    • Внутреннее исключение: TargetInvocationException: «Исключение было выбрано целью вызова».
      • Внутреннее исключение: DirectoryNotFoundException: "Не удалось найти часть пути ': \ SVN \ WpfApplication8 \ WpfApplication8 \ Bin \ Debug \ Images \ elf.png C'."

Внутренний-внутренний-исключение трассировки стека показывает, что исходное исключение (The DirectoryNotFoundException) выбрасывают линией, который создает в CroppedBitmap. Я не знаю, почему эта строка будет пытаться читать с диска, или почему это не работает, когда XAML как-далеко-I-can-tell-эквивалент отлично работает.

Так как я знаю, 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, которая отличается?

ответ

4

Магия оказалась в объекте BitmapImage BaseUri. BaseUri, по-видимому, служит в качестве «текущего каталога», к которому относится UriSource.

Когда мой BitmapImage загружался из XAML, BaseUri магически настраивался на «pack: // application: ,,,/WpfApplication8; component/window1.xaml». Когда я модифицировал фрагмент кода # 4, чтобы явно установить fullImage.BaseUri на это же значение перед созданием CroppedBitmap, все сработало.

Почему он работал с XAML(и от просто-BitmapImage-без CroppedBitmap)

Так где же эта магическая ценность BaseUri взялось?

BaseUri является частью интерфейса IUriContext. IUriContext.BaseUri устанавливается в двух местах в сборках WPF, и между моими различными примерами мне удалось ударить и из них. Неудивительно, что я был в замешательстве.

  • BamlRecordReader.ElementInitialize. Загрузчик BAML автоматически устанавливает BaseUri в любое время, когда он загружает элемент, реализующий IUriContext. Это объясняет, почему работали мои примеры # 1 и # 2: они загружались из скомпилированного ресурса BAML.
  • Image.UpdateBaseUri (называемый при изменении свойства Source). Это проверяет, реализует ли источник IUriContext, и если да, то устанавливает его BaseUri. Это объясняет, почему мой пример №3 работал: нажатие BitmapImage в GUI заставляло его получить правильный путь поиска.

Он ищет только изображения в ресурсах EXE, когда BaseUri установлен в волшебный пакет: // URI. Без этого (как это происходит, когда все создается в коде и не вставляется в графический интерфейс), он выглядит только на диске.

Исправление

Как было отмечено выше, я мог бы жестко закодировать BaseUri. Но BaseUriHelper класс обеспечивает лучшее исправление:

fullImage.BaseUri = BaseUriHelper.GetBaseUri(this); 

Это устанавливает fullImage иметь тот же BaseUri как окно (this). Если это сделано до создания CroppedBitmap, все работает.

 Смежные вопросы

  • Нет связанных вопросов^_^