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

如何通过源代码生成器读取XAML/BAML以生成C#代码?

借助XAML/BAML实现增量源代码生成的可行方案

方案1:将XAML标记为AdditionalText,直接读取原始XAML内容

默认XAML的生成操作是Page,无法被AdditionalTextsProvider捕获,但可以通过修改项目文件(.csproj),让XAML文件同时保留原有编译逻辑并被生成器识别:

<ItemGroup>
  <!-- 让所有XAML文件同时作为Page和AdditionalText -->
  <Page Update="**/*.xaml">
    <IsAdditionalText>true</IsAdditionalText>
  </Page>
</ItemGroup>

配置完成后,即可在增量生成器中通过AdditionalTextsProvider获取XAML文件,读取原始内容并解析:

public void Initialize(IncrementalGeneratorInitializationContext context)
{
    // 获取所有标记为AdditionalText的XAML文件
    var xamlFiles = context.AdditionalTextsProvider
        .Where(text => text.Path.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase));

    // 基于XAML内容生成代码
    context.RegisterSourceOutput(xamlFiles, (spc, text) =>
    {
        string xamlContent = text.GetText(spc.CancellationToken)?.ToString();
        if (string.IsNullOrEmpty(xamlContent)) return;

        // 这里添加XAML解析和代码生成逻辑
        // 例如解析XAML中的控件结构,生成对应的C#辅助代码
        string generatedCode = GenerateCodeFromXaml(xamlContent, text.Path);
        spc.AddSource($"{Path.GetFileNameWithoutExtension(text.Path)}.g.cs", generatedCode);
    });
}

方案2:读取嵌入程序集的BAML(适用于依赖项目的XAML)

如果需要处理已编译为BAML并嵌入到程序集的XAML(比如来自依赖库的内容),可以通过CompilationProvider获取编译上下文,遍历元数据引用读取嵌入资源:

public void Initialize(IncrementalGeneratorInitializationContext context)
{
    var compilationWithBaml = context.CompilationProvider
        .Select((compilation, ct) =>
        {
            // 遍历所有元数据引用(依赖程序集)
            foreach (var reference in compilation.References)
            {
                if (compilation.GetAssemblyOrModuleSymbol(reference) is not IAssemblySymbol assemblySymbol)
                    continue;

                // 获取程序集的元数据读取器
                if (reference is PortableExecutableReference peRef && peRef.GetMetadataReader(out var reader))
                {
                    // 遍历嵌入资源,查找BAML文件
                    foreach (var resource in reader.ManifestResources)
                    {
                        if (resource.Name.EndsWith(".baml", StringComparison.OrdinalIgnoreCase))
                        {
                            // 读取BAML资源内容
                            var resourceData = reader.GetBlobBytes(resource.Value);
                            if (resourceData != null)
                            {
                                // 使用XamlReader解析BAML(需引用WPF相关程序集)
                                using var stream = new MemoryStream(resourceData);
                                var bamlReader = new System.Windows.Markup.Baml2006Reader(stream);
                                var xamlObject = System.Windows.Markup.XamlReader.Load(bamlReader);
                                
                                // 基于解析后的对象生成代码
                                // ...
                            }
                        }
                    }
                }
            }
            return compilation;
        });

    context.RegisterSourceOutput(compilationWithBaml, (spc, _) =>
    {
        // 输出生成的代码
    });
}

注意:当前项目的XAML编译后的BAML不会在增量生成阶段出现在元数据引用中(因为当前项目还未完成编译),此方案仅适用于处理依赖项目的BAML资源。

方案3:通过MSBuild目标传递XAML/BAML数据(复杂场景)

如果上述两种方案无法满足需求,可以自定义MSBuild目标,在编译前将XAML内容或BAML路径写入临时文件,再将临时文件标记为AdditionalText供生成器读取。此方案适合需要对XAML编译流程做自定义处理的场景,但配置复杂度较高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 04:30:25