Henry Jooste Ответов: 2

Динамически загружать XAML-файл с кодом


Привет. Я хотел бы загрузить внешний XAML-файл (включая код) во время выполнения. Мне удалось загрузить содержимое файла XAML:
try
{
    FileStream Fs = new FileStream(@"C:/XAML Files/ucMain.xaml", FileMode.Open);
    Page grdToLoad = new Page();
    grdToLoad.Height = 210;
    grdToLoad.Width = 400;
    grdToLoad = System.Windows.Markup.XamlReader.Load(Fs) as Page;
    gridMain.Children.Add(grdToLoad);
    Fs.Close();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

Это работает идеально, но я, кажется, не могу загрузить код позади. Я пробовал использовать x: Code, но постоянно получаю ошибку:
"Не удалось создать "щелчок" из текста "щелчок". "номер строки" 4 "и позиция строки "26"."

файл XAML:
<Grid

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  <Button Name="butMain" Click="Clicked">Click Me!</Button>
  <x:Code><![CDATA[
    void Clicked(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Hello World!");
    }
  </x:Code>
</Grid>


Если я удалю код x:и событие Click, все, кажется, работает нормально. Можно ли загрузить файл. cs во время выполнения вместо использования x: Code? Если нет, то как я смогу исправить эту ошибку?

Заранее спасибо.

2 Ответов

Рейтинг:
2

#realJSOP

Почему бы вам не попробовать создать UserControl, содержащий ваш xaml? Таким образом, вы получаете все преимущества наличия кода позади и можете создать экземпляр кода в своем вызывающем методе:

this.gridMain.Children.Add(new MyUserControl());


Таким образом, вы поддерживаете надлежащую разделенность и можете подключить событие нажатия кнопки либо в вашем пользовательском элементе управления, либо в Родительском окне/элементе управления.


Рейтинг:
0

Jon McKee

<Grid

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  <Button Name="butMain" Click="Clicked">Click Me!</Button>
  <x:Code><![CDATA[
    void Clicked(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Hello World!");
    }
  ]]> <!-- Forgot the closing tag -->
  </x:Code>
</Grid>

Вы забыли закрывающий тег для раздела CDATA. Я предполагаю, что из вашего примера вы используете файл site-of-origin, но я бы настоятельно рекомендовал переосмыслить это, если это так. твой XAML-файл, а не что-то внутренне внешнее. Можно установить действие при построении "страницы", который будет компилировать код XAML в BAML-код-файла, внедренного в сборку. Это не только уменьшает количество отдельных файлов в вашем релизе, но и позволяет легко загружать их с помощью:
Page page = Application.LoadComponent(new Uri("/Page1.xaml", UriKind.Relative)) as Page;
if (page != null)
  gridMain.Children.Add(page);

Это будет работать просто отлично, но вы будете предупреждены, что Page не предназначен для того, чтобы быть ребенком чего-либо другого, кроме Window или Frame Это можно было бы легко исправить, просто обернув загруженный Page в Frame и добавляя, что в детстве к Grid.
Пример:
Uri uri = new Uri("/Page1.xaml", UriKind.Relative);
Page page = Application.LoadComponent(uri) as Page;
Frame frame = new Frame();
frame.Content = page;
//Or frame.Source = uri; This lets WPF control the loading for you.
gridMain.Children.Add(frame);


Мой полный рабочий код:
<!-- MainWindow.xaml -->
<Window x:Class="Testing_xClass_and_xCode.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:Testing_xClass_and_xCode"

        mc:Ignorable="d"

        Title="MainWindow" Height="350" Width="525">
    <Grid Name="gridMain" />
</Window>
<!-- Page1.xaml -->
<Page x:Class="Testing_xClass_and_xCode.Page1"

      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 

      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 

      xmlns:local="clr-namespace:Testing_xClass_and_xCode"

      mc:Ignorable="d" 

      d:DesignHeight="300" d:DesignWidth="300"

      Title="Page1">
    <Grid

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <Button Name="butMain" Click="Clicked">Click Me!</Button>
        <x:Code>
            <![CDATA[
            void Clicked(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Hello World!");
            }]]>
        </x:Code>
    </Grid>
</Page>


//MainWindow.xaml.cs
namespace Testing_xClass_and_xCode
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            try
            {
                Page page = Application.LoadComponent(new Uri("/Page1.xaml", UriKind.Relative)) as Page;
                if (page != null)
                    gridMain.Children.Add(page);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}


Правка: краткое Примечание: как указал Джон Симмонс, вам следует подумать о том, чтобы сделать это UserControl вместо. Один Page предназначен для судоходства. Все что вы делаете это инкапсулируете элементы управления вот почему UserControl существует. Тем не менее, WPF очень гибок и позволит вам делать почти все, что угодно.