Compile/Execute XAML during program runtime

后端 未结 3 1273
悲哀的现实
悲哀的现实 2020-12-12 02:49

I would like to create an WPF Application which retrieves XAML Code from a Database and displays the retrieved code.

Lets say the database return the following code:

相关标签:
3条回答
  • 2020-12-12 03:21

    This is how i solved the problem:

    I have 3 files MainWindow.xaml, MainWindow.xaml.cs and 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 (Note: this file is very large and the most of the stuff is not necessary. You could create a much more simplified solution by following this guide: 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>
    

    Solution:

    The following code snippet will compile the code, created the dll file and use the created dll via reflection. This happens (all) during the application runtime.

    Special thanks to doug for this 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();
            }
        } 
    
    0 讨论(0)
  • 2020-12-12 03:24

    XamlReader class is intened for this purpose. Use its Load method to load the xaml dynamically.

    EDIT - This link here might be of your interest.

    0 讨论(0)
  • 2020-12-12 03:28

    This is an old question, but I want to suggest a better way without compiling in runtime.

    1. Replacing the "click" attribute with "Command". Implement your Relay command or other third party libraries ( Eg: MVVM Light toolkit ) . Also ICommand MVVM implementation would help.
    2. Remove x:Class attribute from xaml of Window node.

    Now you have a loose xaml and task could be done by XamlReader.

    0 讨论(0)
提交回复
热议问题