es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

No es posible recuperar los miembros XAML de Control a través de la compilación de Roslyn.

Dado un INamedTypeSymbol de una ventana WPF, no puedo parecer obtener un ISymbol para los miembros que están definidos en XAML (y luego se compilan como parte del archivo .g.cs generado automáticamente).

Para reproducir el problema que estoy teniendo:

  1. Crea una nueva aplicación WPF en blanco en Visual Studio.
  2. Agrega <TextBlock Name="tb1"/> a MainWindow.xaml.
  3. Coloca el siguiente código en el método MainWindow.xaml.cs e invócalo:
private async void Compile()
{
    var workspace = MSBuildWorkspace.Create();
    workspace.LoadMetadataForReferencedProjects = true;
    var solution = await workspace.OpenSolutionAsync(@"..\..\WpfApp1.Sln");
    var project = solution.Projects.Single();
    // esto no ayuda
    project = project.WithCompilationOptions(project.CompilationOptions.WithMetadataImportOptions(MetadataImportOptions.All)); 
    var comp = await project.GetCompilationAsync();
    INamedTypeSymbol mainWindow = comp.GetTypeByMetadataName(GetType().FullName);
    var members = mainWindow.GetMembers();
    Debug.Assert(members.Any(m => m.Name == nameof(tb1)));
}

Como puedes ver, la afirmación falla y no puedo encontrar el ISymbol que representa el campo de miembro “tb1”.

members.Length  == 2;        // true
members[0].Name == ".ctor"   // true
members[1].Name == "Compile" // true

¿Cómo puedo obtener tb1 sin recurrir a establecer x:FieldModifier="public" en el TextBlock?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una forma de obtener el ISymbol para los miembros definidos en XAML es mediante el uso de la tarea Roslyn XamlCompilation. Esta tarea genera un archivo .g.cs que contiene el código generado para los elementos definidos en XAML. Para habilitar la tarea, agregue la siguiente línea al archivo del proyecto:

    <usewpf>true</usewpf>
    

    Luego, modifique el método Compile() para incluir el archivo generado:

    private async void Compile()
    {
        var workspace = MSBuildWorkspace.Create();
        workspace.LoadMetadataForReferencedProjects = true;
        var solution = await workspace.OpenSolutionAsync(@"..\..\WpfApp1.Sln");            
        var project = solution.Projects.Single();
    
        // Agregar el archivo generado a la compilación
        var generatedFilePath = Path.Combine(Path.GetDirectoryName(project.OutputFilePath), "obj", project.Name + ".g.cs");
        if (File.Exists(generatedFilePath))
        {
            var generatedFile = new FileInfo(generatedFilePath);
            project = project.AddDocument(generatedFile.Name, File.ReadAllText(generatedFile.FullName)).Project;
        }
    
        var comp = await project.GetCompilationAsync();          
        INamedTypeSymbol mainWindow = comp.GetTypeByMetadataName(GetType().FullName);
        var members = mainWindow.GetMembers();
        Debug.Assert(members.Any(m => m.Name == nameof(tb1)));
    }
    

    Esto debería permitirle acceder al miembro tb1 sin establecer x:FieldModifier="public" en el TextBlock.

Comments are closed.