c# wpf xaml runtime code-generation

c# - Compilar/ejecutar XAML durante el tiempo de ejecución del programa



wpf runtime (2)

Me gustaría crear una aplicación WPF que recupere el código XAML de una base de datos y muestre el código recuperado.

Digamos que la base de datos devuelve el siguiente código:

<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid x:Name="mainGrid"> <Button Content="test case 1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="100" Click="TestCase1_OnClick" Height="29"/> </Grid> </Window>

¿Cómo ejecuto este código (o tal vez solo el contenido de mainGrid) durante el tiempo de ejecución?


Así es como resolví el problema:

Tengo 3 archivos MainWindow.xaml, MainWindow.xaml.cs y wpftest.csproj.

MainWindow.xaml:

<Window x:Class="wpftest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Button Content="Button" HorizontalAlignment="Left" Margin="122,75,0,0" VerticalAlignment="Top" Width="75" Click="ButtonBase_OnClick"/> </Grid> </Window>

MainWindow.xaml.cs

namespace wpftest { using System.Windows; /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { MessageBox.Show("Hello world", "does it work?"); } } }

wpftest.csproj (Nota: este archivo es muy grande y la mayoría del material no es necesario. Puede crear una solución mucho más simplificada siguiendo esta guía: Tutorial: Crear un archivo de proyecto MSBuild desde cero )

<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)/$(MSBuildToolsVersion)/Microsoft.Common.props" Condition="Exists(''$(MSBuildExtensionsPath)/$(MSBuildToolsVersion)/Microsoft.Common.props'')" /> <PropertyGroup> <Configuration Condition=" ''$(Configuration)'' == '''' ">Debug</Configuration> <Platform Condition=" ''$(Platform)'' == '''' ">AnyCPU</Platform> <ProjectGuid>{E3FBAE41-AF7E-4C7E-A69E-ADAEAEE76FA2}</ProjectGuid> <OutputType>Library</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>wpftest</RootNamespace> <AssemblyName>wpftest</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <WarningLevel>4</WarningLevel> </PropertyGroup> <PropertyGroup Condition=" ''$(Configuration)|$(Platform)'' == ''Debug|AnyCPU'' "> <PlatformTarget>AnyCPU</PlatformTarget> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin/Debug/</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <PropertyGroup Condition=" ''$(Configuration)|$(Platform)'' == ''Release|AnyCPU'' "> <PlatformTarget>AnyCPU</PlatformTarget> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin/Release/</OutputPath> <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Data" /> <Reference Include="System.Xml" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Xaml"> <RequiredTargetFramework>4.0</RequiredTargetFramework> </Reference> <Reference Include="WindowsBase" /> <Reference Include="PresentationCore" /> <Reference Include="PresentationFramework" /> </ItemGroup> <ItemGroup> <Page Include="MainWindow.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> <Compile Include="MainWindow.xaml.cs"> <DependentUpon>MainWindow.xaml</DependentUpon> <SubType>Code</SubType> </Compile> </ItemGroup> <Import Project="$(MSBuildToolsPath)/Microsoft.CSharp.targets" /> </Project>

Solución:

El siguiente fragmento de código compilará el código, creará el archivo dll y usará el dll creado a través de la reflexión. Esto sucede (todo) durante el tiempo de ejecución de la aplicación.

Gracias especiales a Doug por esta pregunta

private void TestCase4_OnClick(object sender, RoutedEventArgs e) { var globalProperties = new Dictionary<string, string>(); var buildRequest = new BuildRequestData(@"C:/Users/jbu/wpftest/wpftest.csproj", globalProperties, null, new string[] { "Build" }, null); var pc = new ProjectCollection(); var result = BuildManager.DefaultBuildManager.Build(new BuildParameters(pc), buildRequest); Assembly assembly = Assembly.LoadFrom(@"C:/Users/jbu/wpftest/bin/Debug/wpftest.dll"); var instance = assembly.CreateInstance("wpftest.MainWindow") as Window; if (instance != null) { instance.Show(); } }


La clase XamlReader está diseñada para este propósito. Use su método Load para cargar el xaml dinámicamente.

EDITAR - Este enlace aquí podría ser de su interés.