繁体   English   中英

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

[英]How can I change the background of a Canvas in WPF during runtime?

我的情况如下。 我正在为儿子创建一个小数学测验应用程序,并希望在回答每个问题后动态更改画布的背景ImageBrush。 我着手将图像(png)嵌入资源文件中,然后想将它们加载到一个数组中,然后随机选择一个并将其加载到画布中。

我遇到的第一个问题当然是在资源文件中将图像存储为位图的事实。 因此,在Internet上四处浏览之后,我终于想出了如何使用以下帮助程序将它们从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没有描述任何背景,而且...我很困惑。 任何帮助将不胜感激! 谢谢!

我想知道您的画布是透明的,还是在画布顶部有另一个元素。 我将看一下Codeplex上的Snoop,以查看您的可视树并确切地确定正在发生什么。 在移至下一个问题时,也请考虑使用触发器或代码绑定为您设置图像。 然后,您可以使用触发器将背景绑定到模板,或者将包含图像的项目绑定到模板并使其自动更新。

浏览完与ImageBrush相关的各种类,尤其是BitmapImage的类之后,我开始认为StreamSource属性只是引用流,而不是在BitmapImage对象中进行本地复制。 因此,我的辅助方法中的using语句实际上释放了流,因此使BitmapImage的StreamSource为null。 然后,画布又变回为纯白色(#FFFFFFFF)SolidColorBrush(感谢James提醒我Snoop )。

因此,要解决此问题,我改为创建一个私有列表来保存对各种图像流的引用,然后将我的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文档页面中遇到了这一点信息:

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

http://bit.ly/bitmapimagestreamsource

但是,当我尝试将CacheOption枚举设置为BitmapCacheOption.OnLoad时使用原始解决方案时,也会导致相同的问题。 我可能在这里遗漏了一些东西,但是我猜似乎并不那么明显。 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM