Ответ 1
Вы, конечно, много работали над этим. Я думаю, что основная проблема заключается в том, что BitmapCacheOption.None не предотвращает кэширование базового BitmapDecoder (ов).
Для этого есть несколько сложных решений, таких как выполнение GC.Collect(), загрузка 300 небольших изображений из 300 разных Uris и вызов GC.Collect() снова, но простой простой:
Вместо загрузки из Uri просто создайте Stream и передайте его в конструктор BitmapFrame:
var source = new BitmapImage();
using(Stream stream = ...)
{
source.BeginInit();
source.StreamSource = stream;
source.CacheOption = BitmapCacheOption.OnLoad; // not a mistake - see below
source.EndInit();
}
Причина, по которой это должно сработать, заключается в том, что загрузка из потока полностью отключает кеш. Мало того, что источник верхнего уровня не кэшируется, но ни один из внутренних декодеров не кэшируется.
Почему BitmapCacheOption.OnLoad? Это кажется противоречивым, но этот флаг имеет два эффекта: он позволяет кэшировать, если возможно кэширование, и это вызывает нагрузку на EndInit(). В нашем случае кеширование невозможно, поэтому все это приводит к тому, что загрузка происходит немедленно.
Очевидно, вы захотите запустить этот код с вашего потока пользовательского интерфейса, а затем заморозить BitmapSource, чтобы вы могли его переместить.
Вы также можете задаться вопросом, почему я не использовал BitmapCreateOptions.IgnoreImageCache. Помимо того, что кеширование невозможно без какого-либо URI, IgnoreImageCache не полностью игнорирует кеш изображения: он игнорирует его только для чтения. Поэтому, даже если параметр IgnoreImageCache установлен, загруженное изображение все еще вставлено в кеш. Разница в том, что существующее изображение в кеше игнорируется.