2011-08-24 38 views
5

我有一個WPF 4.0應用程序,它使用菜單命令之類的東西中的一些自定義16x16圖標。我想(現在)有兩套圖標,默認的Vista/7-ish和一些XP-ish。我想要的是讓當前的操作系統決定使用哪些圖標。如何在每個系統主題的基礎上定義圖標資源?

現在,我已經在指向特定PNG資源的主題資源字典(即Aero.NormalColor.xaml等)中定義了BitmapImage資源。

<!-- Aero.NormalColor.xaml --> 
<BitmapImage x:Key="IconSave" UriSource="/MyWPFApp;component/Resources/Icons16/Aero/disk.png"/> 

<!-- Luna.NormalColor.xaml --> 
<BitmapImage x:Key="IconSave" UriSource="/MyWPFApp;component/Resources/Icons16/Luna/disk.png"/> 

港九我的應用程序,要顯示一個圖標設置圖像/圖標的源屬性作爲一個靜態資源這些BitmapImages之一。

<Image Source="{StaticResource IconSave}"/> 

的想法是,既然WPF加載自動根據當前的OS和主題上一個主題字典,只有一組BitmapImage的資源會被加載和圖標會神奇地得到相應的。

但是,這不起作用,我在運行時遇到了可怕的「找不到資源」異常。我的直覺是,這是因爲主題文件只能搜索自定義控件,而圖像不是。

Blend 4對這些沒有任何問題,但它已通過在Aero.NormalColor.xaml上定義了它的特殊DesignTimeResources.xaml文件。 VS2010扼流圈,但它也沒有使用DesignData等文件,所以我並不感到驚訝。我目前還有一個單獨的資源字典文件(MainSkin.xaml),它被合併到應用程序資源中。引用樣式等可以在運行時正常工作。

我在正確的軌道上,只是有點不對嗎?我是否需要做一些完全不同的事情才能獲得理想的效果?如果是,需要做些什麼?

回答

5

我發現你可以使用ComponentResourceKey得到這個工作。在你的主題資源字典定義如下

<!-- themes\aero.normalcolor.xaml --> 
<BitmapImage x:Key="{ComponentResourceKey ResourceId=IconSave, TypeInTargetAssembly={x:Type local:CustomControl}}" UriSource="/MyWPFApp;component/Resources/Icons16/Aero/disk.png"/> 

<!-- themes\luna.normalcolor.xaml --> 
<BitmapImage x:Key="{ComponentResourceKey ResourceId=IconSave, TypeInTargetAssembly={x:Type local:CustomControl}}" UriSource="/MyWPFApp;component/Resources/Icons16/Luna/disk.png"/> 

這裏local:CustomControl可以是你的主窗口或您的組件內的自定義控件的資源。有趣的是,只要它是自定義的,它並不重要,所以它確保你強制它加載這些資源。

您還需要更新您的AssemblyInfo.cs確保ThemeInfo着眼於源組件爲主題資源字典有以下

[assembly:ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)] 

現在你的XAML中(控制任何你喜歡的,沒有按」噸有是CustomControl),您可以編寫以下,使資源

<Image Source="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type local:CustomControl}, ResourceId=IconSave}}"/> 

的使用使用DynamicResource還可以使應用程序動態更新時主題更改(而不是靜態資源,這將需要AR estart)。

我認爲可以編寫一個更清潔的ComponentResourceKey實現來隱藏TypeInTargetAssembly(我將繼續介紹),但至少應該讓你工作。


要更新,我剛剛實施了ComponentResourceKey一種改進方法,將着眼於當前執行的程序集,並找到第一的UIElement它可以使用的TypeInTargetAssembly。

public class ThemeResourceKey : ComponentResourceKey 
    { 
     public ThemeResourceKey(String resourceId) 
     { 
      ResourceId = resourceId; 
      var assembly = Assembly.GetExecutingAssembly(); 

      var types = assembly.GetTypes().Where(t => typeof (UIElement).IsAssignableFrom(t)); 
      var uiElementType = types.FirstOrDefault(); 
      if(uiElementType == default(Type)) 
       throw new ArgumentException("No custom UIElements defined within this XAML"); 

      TypeInTargetAssembly = uiElementType; 
     } 
    } 

現在,您可以定義資源字典與此

<!-- themes\aero.normalcolor.xaml --> 
<BitmapImage x:Key="{local:ThemeResourceKey IconSave}" UriSource="/MyWPFApp;component/Resources/Icons16/Aero/disk.png"/> 

和參考這在你的控制如下

<Image Source="{DynamicResource {local:ThemeResourceKey IconSave}}"/> 

這應該證明變得更乾淨。希望有所幫助,並讓我知道你是否有任何問題。

+0

我不得不使用全包URI語法才能使它工作:'pack:// application:,,,, Resources/Icons16/Aero/disk.png'否則,我得到了一個'DirectoryNotFoundException',因爲它是看着C:\出於某種原因。 –

相關問題