You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过反射获取程序集Themes/Generic.xaml的ResourceDictionary实例

问题原因说明

你用Application.LoadComponent加载得到的是全新的ResourceDictionary副本,和WPF运行时内部正在使用的实例完全独立,所以修改不会生效,单独加载报错是因为缺少运行时依赖的其他资源上下文。

实现方案

方案1:遍历已加载资源树(无需反射)

如果目标Generic.xaml已经被合并到应用资源树中,可以直接遍历匹配:

string targetAssemblyName = "你的目标程序集名称";
ResourceDictionary targetDict = null;

// 遍历应用级资源的合并字典
foreach (var dict in Application.Current.Resources.MergedDictionaries)
{
    if (dict.Source != null 
        && dict.Source.OriginalString.Contains(targetAssemblyName) 
        && dict.Source.OriginalString.EndsWith("themes/generic.xaml", StringComparison.OrdinalIgnoreCase))
    {
        targetDict = dict;
        break;
    }
}

// 如果应用级没找到,遍历所有已打开窗口的资源树
if (targetDict == null)
{
    foreach (Window window in Application.Current.Windows)
    {
        foreach (var dict in window.Resources.MergedDictionaries)
        {
            if (dict.Source != null 
                && dict.Source.OriginalString.Contains(targetAssemblyName) 
                && dict.Source.OriginalString.EndsWith("themes/generic.xaml", StringComparison.OrdinalIgnoreCase))
            {
                targetDict = dict;
                goto EndSearch;
            }
        }
    }
}
EndSearch:
// 拿到targetDict后直接修改即可

方案2:反射获取WPF内部缓存的实例(推荐)

WPF会把所有加载过的主题资源缓存到内部的ThemeDictionaryCache中,直接从缓存获取的就是正在使用的实例:

using System.Reflection;
using System.Collections;
using System.Windows;

// 替换为目标程序集中的任意公开类型,用来定位目标程序集
Type typeInTargetAssembly = typeof(目标程序集中的某个公开类型);
Assembly targetAssembly = typeInTargetAssembly.Assembly;
string targetAssemblyName = targetAssembly.GetName().Name;

// 获取WPF内部的ThemeDictionary类型
Type themeDictType = typeof(ResourceDictionary).Assembly
    .GetType("System.Windows.ThemeDictionary");
if (themeDictType == null) return;

// 获取静态缓存字段
FieldInfo cacheField = themeDictType.GetField("_themeDictionaryCache", 
    BindingFlags.NonPublic | BindingFlags.Static);
if (cacheField == null) return;

Hashtable themeCache = (Hashtable)cacheField.GetValue(null);
ResourceDictionary targetDict = null;

foreach (DictionaryEntry entry in themeCache)
{
    ResourceDictionary dict = (ResourceDictionary)entry.Value;
    if (dict.Source != null 
        && dict.Source.OriginalString.Contains(targetAssemblyName) 
        && dict.Source.OriginalString.EndsWith("themes/generic.xaml", StringComparison.OrdinalIgnoreCase))
    {
        targetDict = dict;
        break;
    }
}

// 此处拿到的targetDict就是运行时正在使用的实例,直接修改内容即可
注意事项
  • 修改资源后,只有通过DynamicResource引用该资源的控件会自动更新样式,StaticResource引用的资源已经在加载时完成值解析,不会自动生效,需要手动触发对应控件的重加载逻辑。
  • 缓存中的实例已经完成了所有资源的上下文加载,不会出现你之前遇到的加载错误问题。

内容的提问来源于stack exchange,提问作者CSharpie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 17:15:02