Ответы с форумов MSDN

Программное отображение окна WPF из BAML-файла

Date: 31.12.2018 9:43:52

"Подскажите где можно найти компилятор приложений С# WPF"

MSBuild (https://docs.microsoft.com/ru-ru/visualstudio/msbuild/msbuild?view=vs-2017)

"Мне нужен XAML Designer такой как в Visual Studio"

Если нужно работать только с голым XAML, без Code-behind, можно использовать System.Windows.Markup.XamlReader (https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.markup.xamlreader?view=netframework-4.7.2). Однако, когда доходит до XAML с Code-Behind, задача распарсить все это на уровне исходного кода становится неподъемно сложной. Вместо этого, куда проще собрать проект и проанализировать бинарную сборку через Reflection. 

Вот пример кода для сборки проекта через MSBuild и отображения содержащихся в нем окон.

XAML:

<Window x:Class="WpfBuild.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF Viewer" Height="350" Width="525" WindowState="Maximized">
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <Label Content="Путь к проекту" HorizontalAlignment="Left" Margin="31,31,0,0" VerticalAlignment="Top"/>
        <Label Content="Каталог для вывода" HorizontalAlignment="Left" Margin="31,87,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="tbProject" HorizontalAlignment="Stretch" Height="26" Margin="189,31,10,00" 
                 TextWrapping="Wrap" Text="" VerticalAlignment="Top" />
        <TextBox x:Name="tbOutputDir" HorizontalAlignment="Stretch" Height="26" Margin="189,87,10,10" 
                 TextWrapping="Wrap" Text="" VerticalAlignment="Top"/>
        <Button x:Name="btnBuild" Content="Построить" HorizontalAlignment="Left" Height="25" 
                Margin="31,141,0,0" VerticalAlignment="Top" Width="130" Click="btnBuild_Click"/>
        <Button x:Name="btnView" Content="Просмотр" HorizontalAlignment="Left" Height="25" 
                Margin="189,141,0,0" VerticalAlignment="Top" Width="130" Click="btnView_Click" />
        <ListBox x:Name="lbBamlList" HorizontalAlignment="Left"  Margin="10,189,10,10" 
                 VerticalAlignment="Stretch" Width="198" SelectionChanged="lbBamlList_SelectionChanged"/>
        <Grid x:Name="grid" HorizontalAlignment="Stretch"  Margin="236,190,10,10" VerticalAlignment="Stretch" Background="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />

    </Grid>
</Window>


C#:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Reflection;
using System.Resources;

namespace WpfBuild
{

    public partial class MainWindow : Window
    {
        List<string> BamlList = new List<string>();
        Assembly ass = null;

        public MainWindow()
        {
            InitializeComponent();
            btnView.IsEnabled = false;
        }

        bool BuildProject(string proj, string outdir)
        {
            if (String.IsNullOrEmpty(proj))
            {
                MessageBox.Show("Project path not specified", "Error");
                return false;
            }

            if (String.IsNullOrEmpty(outdir))
            {
                MessageBox.Show("Output path not specified", "Error");
                return false;
            }

            string DotnetPath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.Windows),
                "Microsoft.NET\\Framework\\"
                );

            try
            {
                //найдем самую новую версию MSBuild на этой машине...
                string[] dirs = Directory.GetDirectories(DotnetPath);
                Array.Sort(dirs);

                string MSBuildPath = "";

                for (int i = dirs.Length - 1; i >= 0; i--)
                {
                    string s = Path.Combine(dirs[i], "msbuild.exe");
                    if (File.Exists(s))
                    {
                        MSBuildPath = s; break;
                    }
                }

                if (MSBuildPath == "")
                {
                    throw new FileNotFoundException("Fatal error: MSBuild not found!");
                }

                //соберем проект через MSBuild...
                ProcessStartInfo psi = new ProcessStartInfo();
                psi.FileName = MSBuildPath;
                psi.Arguments = String.Format(
                    "\"{0}\" /property:OutDir=\"{1}\"", proj, outdir
                    );
                psi.WindowStyle = ProcessWindowStyle.Hidden;
                Process pr = Process.Start(psi);
                pr.WaitForExit();
                int code = pr.ExitCode;

                if (code == 0) 
                {
                    MessageBox.Show("Build success");
                    return true; 
                }
                else
                {
                    MessageBox.Show("MSBuild error: " + code.ToString());
                    return false;
                }                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.GetType().ToString());
                return false;
            }
        }

        void ShowWindowFromBaml()
        {
            object val = lbBamlList.SelectedValue;
            if (val == null) return;

            string name = Path.GetFileNameWithoutExtension(val.ToString());

            try
            {
                var types = ass.DefinedTypes;

                //найдем в сборке класс окна, соответствующий по имени baml-файлу
                foreach (TypeInfo type in types)
                {
                    if (type.BaseType == typeof(Window) && type.Name.ToLower() == name.ToLower())
                    {
                        //создадим экземпляр окна и отобразим его в Grid'е
                        Point basepoint = grid.TranslatePoint(new Point(0, 0), this);
                        Window wnd = (Window)Activator.CreateInstance(type);
                        wnd.Owner = this;

                        wnd.Top = basepoint.Y + SystemParameters.CaptionHeight;
                        wnd.Left = basepoint.X;
                        wnd.WindowState = System.Windows.WindowState.Normal;
                        wnd.Show();
                        return;
                    }
                }

                MessageBox.Show("Error: window class not found in assembly");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.GetType().ToString());
            }
        }

        private void btnBuild_Click(object sender, RoutedEventArgs e)
        {
            btnView.IsEnabled = false;
            bool success = BuildProject(tbProject.Text, tbOutputDir.Text);
            if (!success) return;

            try
            {
                //найдем сборку в выходных файлах MSBuild
                string AssPath = Path.Combine(tbOutputDir.Text, Path.GetFileNameWithoutExtension(tbProject.Text) + ".exe");
                ass = Assembly.LoadFrom(AssPath);

                var names = ass.GetManifestResourceNames();

                //найдем все BAML-ресурсы в сборке
                BamlList.Clear();
                foreach (var s in names)
                {
                    var stream = ass.GetManifestResourceStream(s);

                    using (ResourceReader reader = new ResourceReader(stream))
                    {

                        foreach (System.Collections.DictionaryEntry entry in reader)
                        {
                            BamlList.Add(entry.Key.ToString());
                        }
                    }

                }

                lbBamlList.ItemsSource = BamlList;                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.GetType().ToString());
            }
        }

        private void btnView_Click(object sender, RoutedEventArgs e)
        {
            ShowWindowFromBaml(); //отобразим окно для выбранного BAML-файла
        }

        private void lbBamlList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            object val = lbBamlList.SelectedValue;
            if (val != null) btnView.IsEnabled = true;
        }
    }
}




Автор: VadimTagil

Главная страница - Список тем - Репозиторий на GitHub