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

如何从动态加载的DLL的XAML文件获取ResourceDictionary并添加至应用

Avalonia动态加载DLL中样式和资源的正确方式

问题场景

已通过以下代码成功动态加载包含自定义Avalonia控件的Components.dll并使用控件:

var basePath = Directory.GetCurrentDirectory();
var dll = Assembly.LoadFile(Path.Combine(basePath, "Components.dll"));

foreach (var type in dll.GetExportedTypes())
{
  if (type.IsAssignableTo(typeof(IComponentPlugin)))
  {
    var instance = Activator.CreateInstance(type);
    if (instance is IComponentPlugin plugin)
    {
      // Do Stuff
    }
  }
}

但尝试添加DLL中的默认样式和资源时遇到两类错误:

  1. 使用ResourceInclude/StyleInclude时,报错:No precompiled XAML found for avares://DefaultResources.axaml/ (baseUri: avares://DefaultResources.axaml/)
  2. 使用AvaloniaRuntimeXamlLoader加载时,报错:The resource avares://DefaultResources.axaml/ could not be found.

解决方案

1. 先确保资源文件的构建配置正确

在Components.dll的项目中,修改DefaultResources.axaml和DefaultStyle.axaml的属性:

  • 构建操作:设置为AvaloniaResource
  • 复制到输出目录:设置为如果较新则复制或始终复制
    这一步是基础,否则资源不会被正确嵌入到DLL中。

2. 推荐:使用预编译XAML加载(性能更优)

修改IComponentPlugin的方法,传入动态加载的程序集,基于程序集名称构造正确的avares URI:

public ResourceInclude? GetResources(Assembly assembly)
{
    // 基于加载的程序集构造基础URI
    var baseUri = new Uri($"avares://{assembly.GetName().Name}/");
    // 拼接资源文件的相对路径(如果文件在子文件夹,比如Resources/DefaultResources.axaml,就改成对应路径)
    var resourceUri = new Uri(baseUri, "DefaultResources.axaml");
    return new ResourceInclude(baseUri) { Source = resourceUri };
}

public StyleInclude? GetStyle(Assembly assembly)
{
    var baseUri = new Uri($"avares://{assembly.GetName().Name}/");
    var styleUri = new Uri(baseUri, "DefaultStyle.axaml");
    return new StyleInclude(baseUri) { Source = styleUri };
}

主程序调用时传入加载的DLL程序集,并添加到Application:

var basePath = Directory.GetCurrentDirectory();
// 推荐用LoadFrom替代LoadFile,自动处理依赖项
var dll = Assembly.LoadFrom(Path.Combine(basePath, "Components.dll"));

foreach (var type in dll.GetExportedTypes())
{
    if (type.IsAssignableTo(typeof(IComponentPlugin)))
    {
        var instance = Activator.CreateInstance(type);
        if (instance is IComponentPlugin plugin)
        {
            // 添加资源到应用程序资源字典
            var resources = plugin.GetResources(dll);
            if (resources != null)
            {
                Application.Current.Resources.MergedDictionaries.Add(resources);
            }
            // 添加样式到应用程序样式集合
            var style = plugin.GetStyle(dll);
            if (style != null)
            {
                Application.Current.Styles.Add(style);
            }
        }
    }
}

3. 备选:运行时加载XAML(适合未预编译的场景)

如果必须使用AvaloniaRuntimeXamlLoader,直接从动态加载的程序集中读取资源流(避免AssetLoader的识别问题):

// 先确保已安装Avalonia.Markup.Xaml.Loader包
public ResourceDictionary? GetResources(Assembly assembly)
{
    // 资源的完整名称格式:程序集名称.文件路径(斜杠替换为点)
    // 示例:如果文件在根目录,就是Components.DefaultResources.axaml;如果在Resources文件夹,就是Components.Resources.DefaultResources.axaml
    var resourceFullName = $"{assembly.GetName().Name}.DefaultResources.axaml";
    using var stream = assembly.GetManifestResourceStream(resourceFullName);
    if (stream == null) return null;
    return AvaloniaRuntimeXamlLoader.Load<ResourceDictionary>(stream);
}

public Styles? GetStyle(Assembly assembly)
{
    var resourceFullName = $"{assembly.GetName().Name}.DefaultStyle.axaml";
    using var stream = assembly.GetManifestResourceStream(resourceFullName);
    if (stream == null) return null;
    return AvaloniaRuntimeXamlLoader.Load<Styles>(stream);
}

主程序调用时添加到Application:

var resources = plugin.GetResources(dll);
if (resources != null)
{
    Application.Current.Resources.MergedDictionaries.Add(resources);
}
var styles = plugin.GetStyle(dll);
if (styles != null)
{
    Application.Current.Styles.AddRange(styles);
}

常见坑点

  • 不要混淆DLL文件名(比如Components.dll)和程序集名称:程序集名称是项目属性中设置的AssemblyName,必须和avares URI中的名称一致
  • 动态加载时优先用Assembly.LoadFrom,Assembly.LoadFile不会自动加载依赖程序集
  • 资源文件的路径要准确,子文件夹下的文件需要在URI或资源全名中体现层级

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:32:09