【问题标题】:How can I change the background of a Canvas in WPF during runtime?如何在运行时更改 WPF 中画布的背景?
【发布时间】:2010-07-03 05:48:42
【问题描述】:

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

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

【问题讨论】:

  • 如果您在更改背景属性后尝试调整窗口大小会发生什么?我的直觉说这是一个刷新问题。除此之外,该方法可能有问题。首先尝试使其与静态资源一起使用,一旦确定,您可以尝试直接从该方法中进行操作?
  • 这是我最初的想法。我曾尝试调用任何“无效”方法来导致重绘,但什么也没发生。调整大小、最小化、最大化等,也无济于事。不过,我想我想通了,会在几分钟内发布答案。

标签: c# wpf wpf-controls canvas


【解决方案1】:

我想知道您的画布是否是透明的,或者您的画布顶部是否还有其他元素。我会看一下 Codeplex 上的 Snoop,以查看您的可视化树并准确识别正在发生的事情。当您转到下一个问题时,还可以考虑使用触发器或代码绑定为您设置图像。然后,您可以将背景绑定到带有触发器的模板,或包含图像的项目并让它自动更新。

【讨论】:

    【解决方案2】:

    在查看了各种 ImageBrush 相关类之后,尤其是 BitmapImage 的类,我开始认为 StreamSource 属性只是引用流,而不是在 BitmapImage 对象中创建本地副本。因此,我的辅助方法中的 using 语句实际上释放了流,因此使 BitmapImage 的 StreamSource 为空。然后画布恢复为纯白色 (#FFFFFFFF) SolidColorBrush(感谢 James 提醒我 Snoop)。

    因此,为了解决这个问题,我创建了一个私有列表来保存对各种图像流的引用,然后将我的 BitmapImages 指向这些引用。我实现了 IDisposable 以在 GC 出现时释放各种 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 如果你愿意 之后关闭流 位图图像已创建。默认 OnDemand 缓存选项保留访问权限 到流直到位图 需要,并且清理由 垃圾收集器。

    (http://bit.ly/bitmapimagestreamsource)

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

    【讨论】:

      猜你喜欢
      • 2014-03-01
      • 2023-03-08
      • 2019-12-21
      • 2020-07-29
      • 2013-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多