gpt4 book ai didi

wpf - 如何在每个系统主题的基础上定义图标资源?

转载 作者:行者123 更新时间:2023-12-04 14:50:29 27 4
gpt4 key购买 nike

我有一个 WPF 4.0 应用程序,它在菜单命令等内容中使用了一些自定义的 16x16 图标。我想要(现在)两套图标,默认的 Vista/7 风格的和一些 XP 风格的。我想要的是让当前的操作系统确定要使用的图标。

现在,我已经在指向特定 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 之一的 StaticResource。
<Image Source="{StaticResource IconSave}"/>

这个想法是,由于 WPF 会根据当前操作系统和主题自动加载主题字典,因此只会加载一组 BitmapImage 资源,并且图标会神奇地成为合适的图标。

但是,这不起作用,并且我在运行时遇到了可怕的“找不到资源”异常。我的预感是,这是因为主题文件只会搜索自定义控件,而不会搜索 Image。

Blend 4 对这些没有任何问题,但它定义了特殊的 DesignTimeResources.xaml 文件,并在 Aero.NormalColor.xaml 上进行了合并。 VS2010 窒息,但它也无法使用诸如 DesignData 文件之类的东西,所以我并不感到惊讶。我目前还有一个单独的资源字典文件 (MainSkin.xaml),它已合并到应用程序资源中。引用样式等在运行时工作正常。

我是否在正确的轨道上,只是有一些小错误?我是否需要做一些完全不同的事情才能达到预期的效果,如果是,那又是什么?

最佳答案

我发现您可以使用 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,您还可以使应用程序在主题更改时动态更新(而不是需要重新启动的 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;
}
}

您现在可以使用此定义资源字典
<!-- themes\aero.normalcolor.xaml -->
<BitmapImage x:Key="{local:ThemeResourceKey IconSave}" UriSource="/MyWPFApp;component/Resources/Icons16/Aero/disk.png"/>

并在您的控件中引用它,如下所示
<Image Source="{DynamicResource {local:ThemeResourceKey IconSave}}"/>

这应该证明更清洁。希望对您有所帮助,如果您有任何问题,请告诉我。

关于wpf - 如何在每个系统主题的基础上定义图标资源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7180435/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com