我有一个WPF 4.0应用程序,它在菜单命令之类的东西中使用了一些自定义的16x16图标。我希望(目前)有两组图标,默认的Vista/7样式和一些xp样式。我想要的是让当前的操作系统决定使用哪个图标。
现在,我已经在主题资源字典(即Aero.NormalColor)中定义了BitmapImage资源。xaml等),指向特定的PNG资源。
<!-- 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"/>
在我的应用程序的任何地方,想要显示一个图标设置图像/图标的源属性作为一个StaticResource到这些BitmapImages之一。
<Image Source="{StaticResource IconSave}"/>
这个想法是,由于WPF根据当前操作系统和主题自动加载主题字典,因此只会加载一组BitmapImage资源,并且图标将神奇地成为合适的图标。
但是,这不起作用,并且我在运行时得到可怕的"无法找到资源"异常。我的直觉是,这是因为主题文件只搜索自定义控件,而图像不是。
Blend 4在这些方面没有问题,但是它已经定义了它的特殊designtimeresource。xaml文件与Aero.NormalColor.xaml合并。VS2010令人窒息,但它也不能使用像DesignData文件之类的东西,所以我并不感到惊讶。我目前还有一个单独的资源字典文件(MainSkin.xaml),它被合并到应用程序资源中。引用样式等在运行时工作得很好。
我是在正确的轨道上,只是有一些轻微的错误?我是否需要做一些完全不同的事情来达到预期的效果?如果是,该怎么做?
我发现您可以使用ComponentResourceKey使其工作。在主题资源字典中,按如下方式定义资源
<!-- themesaero.normalcolor.xaml -->
<BitmapImage x:Key="{ComponentResourceKey ResourceId=IconSave, TypeInTargetAssembly={x:Type local:CustomControl}}" UriSource="/MyWPFApp;component/Resources/Icons16/Aero/disk.png"/>
<!-- themesluna.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,你还可以使应用程序在主题改变时动态更新(而不是需要重启的StaticResource)。
我认为可能可以编写一个更干净的ComponentResourceKey实现来隐藏TypeInTargetAssembly(我将尝试),但至少这应该让你工作。
为了更新,我刚刚实现了对ComponentResourceKey的改进,它将查看当前执行的程序集,并找到它可以用于TypeInTargetAssembly的第一个UIElement。
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;
}
}
你现在可以用这个
定义资源字典<!-- themesaero.normalcolor.xaml -->
<BitmapImage x:Key="{local:ThemeResourceKey IconSave}" UriSource="/MyWPFApp;component/Resources/Icons16/Aero/disk.png"/>
并在控件中引用它,如下所示
<Image Source="{DynamicResource {local:ThemeResourceKey IconSave}}"/>
这应该证明更干净。希望这对你有帮助,如果有任何问题请告诉我