如何在运行时更改WPF中Canvas的背景?

时间:2010-07-03 05:48:43

标签: c# wpf wpf-controls canvas

我的方案如下。我正在为我的儿子创建一个小数学测验应用程序,并希望在每个问题得到解答后动态更改我的画布的背景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;
    }

从那里我从BitmapImage创建了一个ImageBrush并将其分配给画布的Background属性:

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

不幸的是,这似乎不起作用。当应用程序运行时,背景是纯白色。我的XAML没有描述任何背景......我很困惑。任何帮助将不胜感激!谢谢!

2 个答案:

答案 0 :(得分:1)

我想知道你的画布是否透明,或者你的画布上还有另一个元素。我会看看Codeplex上的Snoop来查看你的可视化树,并确切地确定发生了什么。当您转到下一个问题时,还可以考虑使用触发器或代码绑定为您设置图像。然后,您可以使用触发器将背景绑定到模板,或者将项目绑定到图像并让它自动更新。

答案 1 :(得分:0)

通过各种图像刷相关的类,特别是BitmapImage的寻找后,我开始觉得StreamSource的财产被简单地引用流代替的BitmapImage对象中建立一个本地副本。因此,我的帮助器方法中的using语句实际上释放了流,因此使BitmapImage的StreamSource为null。画布然后回落到纯白色(#FFFFFFFF)的SolidColorBrush(感谢詹姆斯提醒我的Snoop)。

所以,为了解决这个问题,我改为创建了一个私有List来保存对各种图像流的引用,然后将我的BitmapImages指向那些引用。当GC出现时,我实现了IDisposable来释放各种MemoryStream。这是缩写代码:

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]);

修复它,尽管它不够优雅。

在研究时,我确实在MSDN上的BitmapImage.StreamSource文档页面中遇到了一些信息:

  

将CacheOption属性设置为   BitmapCacheOption.OnLoad如果你愿意的话   之后关闭流   BitmapImage已创建。默认   OnDemand缓存选项保留访问权限   直到位图为止的流   需要,清理由。处理   垃圾收集器。

     

http://bit.ly/bitmapimagestreamsource

然而,当我试图用原始溶液与CacheOption枚举set到BitmapCacheOption.OnLoad它导致同样的问题。我可能在这里遗漏了一些东西,但是我想这显而易见的并不是那么明显。 :)