在程序运行时编译/执行XAML

时间:2013-02-21 13:14:21

标签: c# wpf xaml runtime code-generation

我想创建一个WPF应用程序,它从数据库中检索XAML代码并显示检索到的代码。

让我们说数据库返回以下代码:

<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>

如何在运行时执行此代码(或者只是mainGrid的内容)?

3 个答案:

答案 0 :(得分:4)

XamlReader类用于此目的。使用其Load方法动态加载xaml。

编辑 - 此链接here可能符合您的利益。

答案 1 :(得分:2)

这是一个古老的问题,但是我想提出一种更好的方法,而不在运行时进行编译。

  1. 用“命令”代替“点击”属性。实施中继命令或其他第三方库(例如:MVVM Light toolkit )。此外,ICommand MVVM implementation也会有所帮助。
  2. 从xaml的Window节点中删除x:Class属性。

现在您的xaml松了,任务可以由XamlReader完成。

答案 2 :(得分:0)

这就是我解决问题的方法:

我有3个文件MainWindow.xaml,MainWindow.xaml.cs和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 (注意:此文件非常大,并且大部分内容都不是必需的。您可以按照本指南创建更加简化的解决方案:Walkthrough: Creating an MSBuild Project File from Scratch

<?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>

<强>解决方案:

以下代码片段将编译代码,创建dll文件并通过反射使用创建的dll。这在应用程序运行时期间(全部)发生。

特别感谢此doug

stackoverflow question
    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();
        }
    }