Как я могу изменить фон холста в WPF во время выполнения? - PullRequest
1 голос
/ 03 июля 2010

Мой сценарий следующий. Я создаю небольшое приложение по математике для моего сына и хочу динамически менять фоновый рисунок ImageBrush моего холста после ответа на каждый вопрос. Я приступил к вставке своих изображений (pngs) в файл ресурсов и решил, что я буду загружать их в массив, а затем случайным образом выбирать одно и загружать в холст.

Первая проблема, с которой я столкнулся, это, конечно, тот факт, что в файле ресурсов изображения были сохранены как растровые изображения. Так что после некоторого осмотра в Интернете я наконец понял, как преобразовать их из объектов Bitmap в объекты BitmapImage, используя следующий вспомогательный метод:

    private BitmapImage FromResourceBitmap(Bitmap bitmap)
    {
        var result = new BitmapImage();

        using(var stream = new MemoryStream())
        {
            bitmap.Save(stream, ImageFormat.Png);

            stream.Position = 0;

            result.BeginInit();
            result.StreamSource = stream;
            result.EndInit();
        }

        return result;
    }

Оттуда я создал ImageBrush из BitmapImage и назначил его свойству Background фона:

            var brush = new ImageBrush {ImageSource = m_Media.Screens[0]}; // m_Media.Screens[x] returns a BitmapImage...obviously.
            QuestionCanvas.Background = brush;

К сожалению, это не похоже на работу. Когда приложение работает, фон чисто белый. Мой XAML не описывает никаких фонов и ... ну, я в замешательстве. Любая помощь будет принята с благодарностью! Спасибо!

Ответы [ 2 ]

1 голос
/ 03 июля 2010

Мне интересно, возможно, ваш холст прозрачный, или у вас есть другой элемент поверх холста.Я бы взглянул на Snoop на Codeplex, чтобы посмотреть на ваше визуальное дерево и точно определить, что происходит.Также рассмотрите возможность использования триггеров или привязки кода для установки изображения при переходе к следующему вопросу.Затем вы можете просто привязать фон к шаблону с помощью триггера или элемент, содержащий изображение, и автоматически обновить его.

0 голосов
/ 04 июля 2010

После просмотра различных классов, связанных с ImageBrush, особенно класса BitmapImage, я начал думать, что свойство StreamSource просто ссылается на поток, а не делает локальную копию в объекте BitmapImage.Таким образом, оператор using в моем вспомогательном методе фактически освобождает поток и поэтому делает StreamSource объекта BitmapImage нулевым.Затем холст вернулся к белому (#FFFFFFFF) SolidColorBrush (спасибо Джеймсу за напоминание о Snoop ).

Итак, чтобы исправить это, я вместо этого создал приватный список для храненияссылки на различные потоки изображений, а затем указать мои BitmapImages на эти ссылки.Я реализовал IDisposable для выпуска различных MemoryStreams, когда появился GC.Вот сокращенный код:

public class Media : IDisposable
{
    private readonly List<BitmapImage> m_Screens = new List<BitmapImage>();
    private readonly List<MemoryStream> m_BackingStreams = new List<MemoryStream>();

    public BitmapImage MainScreen { get; private set; }

    public List<BitmapImage> Screens
    {
        get
        {
            return m_Screens;
        }
    }

    public Media()
    {
        LoadScreens();
    }

    private void LoadScreens()
    {
        m_BackingStreams.Add(FromResourceBitmap(Properties.Resources.Screen_01));
        m_BackingStreams.Add(FromResourceBitmap(Properties.Resources.Screen_02));
        m_BackingStreams.Add(FromResourceBitmap(Properties.Resources.Screen_03));
        m_BackingStreams.Add(FromResourceBitmap(Properties.Resources.Screen_04));
        m_BackingStreams.Add(FromResourceBitmap(Properties.Resources.Screen_05));

        foreach (var stream in m_BackingStreams)
        {
            m_Screens.Add(FromResourceStream(stream));
        }
    }

    private BitmapImage FromResourceStream(Stream stream)
    {
        var result = new BitmapImage();

        result.BeginInit();
        result.StreamSource = stream;
        result.EndInit();

        return result;
    }

    private MemoryStream FromResourceBitmap(Bitmap bitmap)
    {
        var stream = new MemoryStream();

        bitmap.Save(stream, ImageFormat.Png);

        return stream;
    }

    public void Dispose()
    {
        if (m_BackingStreams.Count == 0 || m_BackingStreams == null) return;

        foreach (var stream in m_BackingStreams)
        {
            stream.Close();
            stream.Flush();
        }
    }

А вот как это выглядело, когда я на самом деле устанавливал фон моего Canvas во время выполнения:

MainMenuCanvas.Background = new ImageBrush(m_Media.Screens[0]);

Это исправило это, столь же изящно, какэто может быть.

Во время исследования я наткнулся на эту небольшую информацию на странице документации BitmapImage.StreamSource в MSDN:

Установите свойство CacheOption в BitmapCacheOption.OnLoad, если выхотите закрыть поток после создания BitmapImage.Параметр кэширования OnDemand по умолчанию сохраняет доступ к потоку до тех пор, пока не потребуется растровое изображение, а очистка выполняется сборщиком мусора.

(http://bit.ly/bitmapimagestreamsource)

Однако, когда я попытался использовать исходное решение с набором перечислений CacheOption для BitmapCacheOption.OnLoad, это привело к той же проблеме.Я могу что-то упустить здесь, но очевидное не так очевидно, я думаю.:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...