【问题标题】:Compile/Execute XAML during program runtime在程序运行时编译/执行 XAML
【发布时间】:2013-02-06 19:57:21
【问题描述】:

我想创建一个 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 的内容)?

【问题讨论】:

    标签: c# wpf xaml runtime code-generation


    【解决方案1】:

    XamlReader 类就是为此目的而设计的。使用其Load 方法动态加载xaml。

    编辑 - 此链接 here 可能会引起您的兴趣。

    【讨论】:

    • 据我所知 XamlReader 不适用于事件处理程序 (Click="TestCase1_OnClick")
    • 是的,你不能用它创建处理程序,因为它不再是loose XAML。只能加载松散的 XAML。
    • 为什么要从数据库加载 XAML。如果您解释您要达到的目标,也许可以建议替代实现。例如,我宁愿在内部构建模板,然后从 DB 中获取参数,而不是将 Xaml 存储在 DB 中。
    • @Joel - 我认为你应该重新设计你的代码。但是,如果你想坚持下去,你可以使用CodeDom 来动态创建处理程序。此处链接 elegantcode.com/2010/12/21/… 可能是您感兴趣的。
    • 没有数据库,我只是创建了一个案例来指出问题。真正的问题要复杂得多。但是,让我们试一试,这是我试图实现的目标:我收到了一个在 XML 文件中定义的用户界面和一个来自 web 服务的相应的 c# 代码隐藏文件。 XML 文件必须解析为 XAML。然后我必须以某种方式显示生成的 XAML 文件。基本上我必须在运行时用 xml 文件创建一个用户界面。
    【解决方案2】:

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

    1. 将“click”属性替换为“Command”。实现您的 Relay 命令或其他第三方库(例如:MVVM Light toolkit ) . ICommand MVVM implementation 也会有所帮助。
    2. 从 Window 节点的 xaml 中移除 x:Class 属性。

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

    【讨论】:

      【解决方案3】:

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

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

      解决方案:

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

      特别感谢dougstackoverflow 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();
              }
          } 
      

      【讨论】:

        猜你喜欢
        • 2012-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-11
        • 1970-01-01
        • 2010-10-06
        • 1970-01-01
        • 2021-12-31
        相关资源
        最近更新 更多