2010-07-03 109 views
1

我的場景如下。我爲我的兒子創建了一個小數學測驗應用程序,並希望在每個問題得到回答後動態更改畫布的背景ImageBrush。我開始將我的圖像(pngs)嵌入到資源文件中,並且認爲我會將它們加載到數組中,然後隨機選擇一個並將其加載到畫布中。如何在運行時更改WPF中的Canvas背景?

我碰到的第一個問題當然是在資源文件中圖像被存儲爲位圖。所以經過一些在互聯網上四處尋找,我終於想通了,如何讓他們從位圖轉換使用下面的輔助方法的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的一個圖像刷,並將其分配給背景畫布的屬性:

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

不幸的是,這似乎並不奏效。當應用程序運行時,背景是純白色的。我的XAML沒有描述任何背景,並且......我很困惑。任何幫助將不勝感激!謝謝!

+0

如果在更改背景屬性後嘗試調整窗口大小,會發生什麼情況?我的直覺認爲這是一個更新的問題。除此之外,該方法可能有問題。嘗試使用靜態資源首先工作,一旦這是堅實的,你可以試着直接從方法中做到這一點? – keyle 2010-07-03 07:49:03

+0

這就是我最初的想法。我曾嘗試調用任何「無效」方法來重繪,但沒有發生任何事情。調整大小,最小化,最大化等等,也沒有做任何事情。不過,我想我已經想清楚了,並會在幾分鐘後發佈答案。 – Mateo 2010-07-03 22:02:10

回答

0

查看各種ImageBrush相關類,尤其是BitmapImage的相關類後,我開始認爲StreamSource屬性只是簡單地引用流而不是在BitmapImage對象中創建本地副本。所以,我的幫助器方法中的using語句實際上釋放了流,因此使BitmapImage的StreamSource爲空。然後畫布回落到純白色(#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(); 
     } 
    } 

而且這裏是它看起來,當我在運行時實際設置我的畫布的背景,如:

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

問題解決了,因爲不雅,因爲它可能。

雖然研究我沒有碰到過在BitmapImage.StreamSource文檔頁面信息的這一點上MSDN:

,如果你想 的CacheOption屬性設置爲 BitmapCacheOption.OnLoad後關閉流 BitmapImage已創建。默認的 OnDemand緩存選項保留對流的訪問 ,直到需要位圖 ,並且清理由 垃圾回收器處理。

http://bit.ly/bitmapimagestreamsource

然而,當我試圖用原來的解決方案與CacheOption枚舉集到BitmapCacheOption.OnLoad它導致了同樣的問題。我可能在這裏錯過了一些東西,但顯然我猜不是那麼明顯。 :)

1

我想知道如果你的畫布是透明的,或者你可能在畫布上有另一個元素。我會看看Codeplex上的Snoop,看看你的視覺樹,並確切地確定發生了什麼。當您轉到下一個問題時,還要考慮使用觸發器或代碼綁定來爲您設置圖像。然後,您可以將背景與觸發器綁定到模板,或者將圖像保存在自動更新的項目中。

+0

謝謝你讓我想起Snoop! – Mateo 2010-07-03 22:03:52

相關問題