powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / xaml cdata
13 сообщений из 13, страница 1 из 1
xaml cdata
    #39596628
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день.

Взял пример xamlparser вида:

MainWindow.xaml
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<Window x:Class="XAMLParser.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="XAML Parser" Height="600" Width="800" Topmost="False">
    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  Name="cnvsObjects" Height="400"/>
        <TextBox TextWrapping="Wrap" AcceptsReturn="True" Name="xamlEditor" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="120"></TextBox>
        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Click="Button_Click">XAML!</Button>
    </StackPanel>     
</Window>



MainWindows.xaml.cs
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
//using System.Windows.Markup;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xaml;
using System.IO;

namespace XAMLParser
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            XamlXmlReader xamlReader = new XamlXmlReader(new StringReader(xamlEditor.Text));
            XamlObjectWriter xamlWriter = new XamlObjectWriter(xamlReader.SchemaContext);

            while (xamlReader.Read())
            {
                if ((xamlReader.NodeType == XamlNodeType.StartMember) && (xamlReader.Member.Name == "Class"))
                {
                    xamlReader.Skip();
                }
                
                xamlWriter.WriteNode(xamlReader);
            }

            cnvsObjects.Children.Clear();
            cnvsObjects.Children.Add((UIElement)xamlWriter.Result);
        }
    }
}




Теперь пытаюсь в редактируемое окно приложения вставить текстовый файлик xaml вида:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
<UserControl
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" 
mc:Ignorable="d">
<Grid>
<Button Width="133" Height="24" Name="btnExitApp" Click="btnExitApp_Clicked" Content="Exit Application"/>
<x:Code>
<![CDATA[
private void btnExitApp_Clicked(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
]]>
</x:Code>
</Grid>
</UserControl>



Получаю:
ArgumentException: Не удается привязать целевой метод, поскольку его сигнатура или прозрачность безопасности несовместима с сигнатурой или прозрачностью безопасности типа делегата.
Если из кнопки убрать Click="btnExitApp_Clicked", то кнопка нормально отображается.
Как побороть? Какие советы?
...
Рейтинг: 0 / 0
xaml cdata
    #39596647
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я конечно не уверен, так как таким способом не пользовался, но по логике вещей, код должен быть скомпилирован для выполнения, когда вы загружаете XAML файл с помощью XAML reader'а, этого не происходит.
Сам по себе метод существовать не может, он может существовать только в рамках какого то типа.
Если создать ResourceDictionary и вставить туда ваш UserControl он при сборке VS начнет ругаться, что в файле ресурсе не указано имя класса (x:Class), в который этот метод будет добавлен при компиляции.

То есть, нужно перед тем как загружать XAML загрузить сборку в текущий AppDomain в котором будет реализована логика работы вашего метода.

Но это не точно, сам я таким не пользуюсь.
Еще можно добавить к этой теме, что существует 2 XamlReader,
один находится в пространстве имён System.Windows.Markup.XamlReader, а второй в System.Xaml.XamlReader, в 1 случае это полноценный класс, а во втором абстрактны, который наследует XamlXmlReader.
Но результат у обоих один
...
Рейтинг: 0 / 0
xaml cdata
    #39596729
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
какая у вас цель? лично я не вижу, не 1 причины использовать CodeBehind файлы, на много проще будет реализовать задуманное без всяких CodeBehind классов.
Могу скинуть пример, но в примере будет 2 поля, 1 поле с XAML кодом представления, 2 поле с C# кодом модели представления. Всё это динамически загружается и вставляется в ContentControl.
...
Рейтинг: 0 / 0
xaml cdata
    #39596848
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Идея взята с официального мискрософт:
https://docs.microsoft.com/ru-ru/dotnet/framework/wpf/advanced/code-behind-and-xaml-in-wpf#Prerequisites
То есть делать так получается можно. Вопрос как реализовать выполнение хотя бы этого официального примера из документации.
...
Рейтинг: 0 / 0
xaml cdata
    #39596849
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman Mejtes,

Ваш пример бы с удовольствием изучил.
...
Рейтинг: 0 / 0
xaml cdata
    #39596869
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
microbashИдея взята с официального мискрософт:
https://docs.microsoft.com/ru-ru/dotnet/framework/wpf/advanced/code-behind-and-xaml-in-wpf#Prerequisites
То есть делать так получается можно. Вопрос как реализовать выполнение хотя бы этого официального примера из документации.
Если вы просто создадите UserControl это будет работать без проблем, по крайней мере у меня работало.
суть в том, что когда вы собираете приложение эта часть кода будет размещена в классе указанном в свойстве x:Class корневого элемента и там скомпилировано. Метод, как я уже писал, не может существовать абы кабы, где попало, метод может быть только частью определенного типа, C# это полностью объектно-ориентированный язык программирования.
Даже в статье, которую вы приложили сказано, что не рекомендуется применять этот подход. Так как он не очевидный, найти этот кусок кода будет крайне сложно, особенно если XAML файл будет в 2-3 экрана.

про цель использования динамической загрузки кода вы так и не сказали, если это не тайна, лучше напишите.
...
Рейтинг: 0 / 0
xaml cdata
    #39596918
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman MejtesЕсли вы просто создадите UserControl это будет работать без проблем, по крайней мере у меня работало.


Ну так я разве не с UserControl экспериментирую... Вроде да.

Roman Mejtesсуть в том, что когда вы собираете приложение эта часть кода будет размещена в классе указанном в свойстве x:Class корневого элемента и там скомпилировано. Метод, как я уже писал, не может существовать абы кабы, где попало, метод может быть только частью определенного типа, C# это полностью объектно-ориентированный язык программирования.


Значит надо добавить x:Class в xaml? Пробовал по-разному, пока не помогло.

Roman MejtesДаже в статье, которую вы приложили сказано, что не рекомендуется применять этот подход. Так как он не очевидный, найти этот кусок кода будет крайне сложно, особенно если XAML файл будет в 2-3 экрана.

Ну у меня то пока нету файлов на 2-3 экрана. Так что пока таких сложностей не вижу.


Roman Mejtesпро цель использования динамической загрузки кода вы так и не сказали, если это не тайна, лучше напишите.
Посмотреть как работает xaml, baml, сборки и др. Конкретно от xaml хочется вытягивать его в виде текста по сети.
...
Рейтинг: 0 / 0
xaml cdata
    #39597505
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
XAML файл главной формы
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
<Window x:Class="WpfApp4.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"
        mc:Ignorable="d"
        Title="MainWindow" SizeToContent="WidthAndHeight">
    <Window.Resources>
        <ResourceDictionary>
            <Style x:Key="CodeEditor" TargetType="{x:Type TextBox}">
                <Setter Property="TextWrapping" Value="NoWrap"/>
                <Setter Property="AcceptsReturn" Value="True"/>
                <Setter Property="Height" Value="150"/>
                <Setter Property="Margin" Value="5"/>
            </Style>
        </ResourceDictionary>
    </Window.Resources>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ContentPresenter Name="content" Margin="5" />
        <TextBox Name="xamlEditor" Grid.Row="1" Style="{StaticResource CodeEditor}" xml:space="preserve"><![CDATA[
<ContentControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" x:Name="PART_Message" Margin="5" AcceptsReturn="True"/>
        <Button  Grid.Row="1" Content="Show message" Margin="5" Command="{Binding MsgCommand, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=PART_Message}"/>
        <Button  Grid.Row="2" Content="Exit" Margin="5" Command="{Binding ExitCommand, Mode=OneWay}"/>
    </Grid>
</ContentControl>
]]>
        </TextBox>
        <TextBox Name="codeEditor" Grid.Row="2" Style="{StaticResource CodeEditor}" xml:space="preserve"><![CDATA[
using System.Windows;
using System.Windows.Input;
using WPF.ViewModels;

public class ViewModelExample : BaseViewModel
{
    private ICommand _exitCommand;
    public ICommand ExitCommand
    {
        get
        {
            return _exitCommand ?? (_exitCommand = new RelayCommand(OnExit));
        }
    }

    private void OnExit(object obj)
    {
        Application.Current.Shutdown(0);
    }

    private ICommand _msgCommand;
    public ICommand MsgCommand
    {
        get
        {
            return _msgCommand ?? (_msgCommand = new RelayCommand(OnMessage));
        }
    }

    private void OnMessage(object obj)
    {
        if (obj is string)
        {
            var messageString = (string)obj;
            MessageBox.Show(messageString);
        }
    }
}]]>
        </TextBox>
        <StackPanel Grid.Row="3" Orientation="Horizontal" Margin="5">
            <Button Padding="10,5" Click="Button_Click">Generate</Button>
        </StackPanel>
    </Grid>
</Window>


CodeBehind класс формы
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.Windows;
using WPF.ViewModels;

namespace WpfApp4
{
    /// <summary> Класс формы </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var model = LoadModel(codeEditor.Text);
            var view = LoadView(xamlEditor.Text);
            view.DataContext = model;
            content.Content = view;
        }

        //Метод который динамически сгенерирует представление из XAML
        private FrameworkElement LoadView(string xaml)
        {
            return (FrameworkElement)System.Windows.Markup.XamlReader.Parse(xaml);
        }

        //Метод который сгенерирует динамическую модель представления из кода
        private IViewModel LoadModel(string source)
        {
            using (var compiler = new CSharpCodeProvider())
            {

                //Задаем параметры комплиции
                var compileParams = new CompilerParameters
                {
                    IncludeDebugInformation = true,
                    GenerateInMemory = false
                };
                //Заполняем список ссылок из текущий сборки
                foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                {
                    Debug.Print($"References: {assembly.Location}");
                    compileParams.ReferencedAssemblies.Add(assembly.Location);
                }
                //Компилируем сборку
                var compileResult = compiler.CompileAssemblyFromSource(compileParams, source);
                //Проверяем и выводим в отладку ошибки
                if (compileResult.Errors.Count > 0)
                {
                    foreach (CompilerError error in compileResult.Errors)
                    {
                        Debug.Print($"Line: {error.Line}; {error.ErrorText}");
                    }
                    foreach (string output in compileResult.Output)
                    {
                        Debug.Print($">{output}");
                    }
                    //Так как код не скомпилировался без ошибок кидаем исключение
                    throw new Exception();

                }
                //Находим тип реализующий IViewModel
                var viewModelTypes = compileResult.CompiledAssembly.GetTypes();
                foreach (var vmType in viewModelTypes)
                {
                    if (vmType.GetInterface(nameof(IViewModel)) != null)
                    {
                        return (IViewModel)Activator.CreateInstance(vmType);
                    }
                }
                //Есть тип не найден, выкидываем исключение
                throw new Exception();
            }
        }
    }
}


Немного базовых классов, они нужны, чтоб найти нужный тип модели представления и он имел необходимую реализацию, а так же простейший класс команд, в продакшн нужна нормальная версия класса которую нагуглите
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
using System;
using System.ComponentModel;
using System.Windows.Input;

namespace WPF.ViewModels
{
    //Декларируем модель представления
    public interface IViewModel : INotifyPropertyChanged { }
    public abstract class BaseViewModel : IViewModel
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    //Реализуем простейший класс команд, нормальную реализацию нагуглить 1 минута времени
    public class RelayCommand : ICommand
    {
        private readonly Action<object> _action;
        public RelayCommand(Action<object> action) { _action = action; }
        public event EventHandler CanExecuteChanged;
        bool ICommand.CanExecute(object parameter) { return true; }
        void ICommand.Execute(object parameter) { _action?.Invoke(parameter); }
    }

}
...
Рейтинг: 0 / 0
xaml cdata
    #39597936
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman Mejtes,

Ваш код у меня собрался, запустился, и главное вроде бы работает. Супер!
...
Рейтинг: 0 / 0
xaml cdata
    #39599696
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman Mejtes,

можете еще подсказать, как можно добавить элементы в xamlEditor, чтобы их видел codeEditor по имени?

Т.е. вот здесь нужно чтобы элемент "status_message" был виден в behind-code.
Может хорошо бы здесь как-то объявить пространство имен, т.к. у меня эти два блока как бы отдельный независимый модуль приложения.

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
<ContentControl
     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" mc:Ignorable="d"
     MinHeight="600" MinWidth="700" MaxHeight="600" MaxWidth="700" Height="600" Width="700">
    <DockPanel>
     <StatusBar DockPanel.Dock="Bottom" Name="status">
        <StatusBarItem>
            <TextBlock Name="status_message"/>
        </StatusBarItem>
     </StatusBar>
     <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" x:Name="PART_Message" Margin="5" AcceptsReturn="True"/>
        <Button  Grid.Row="1" Content="Show message" Margin="5" Command="{Binding MsgCommand, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=PART_Message}"/>
        <Button  Grid.Row="2" Content="Exit" Margin="5" Command="{Binding ExitCommand, Mode=OneWay}"/>
        <Button  Grid.Row="3" Content="NewCommand" Margin="5" Command="{Binding MyCommand, Mode=OneWay}"/>
    </Grid>
    </DockPanel>
</ContentControl>



Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
using System.Windows;
using System.Windows.Input;
using WPF.ViewModels;

public class ViewModelExample : BaseViewModel
{
    private ICommand _exitCommand;
    public ICommand ExitCommand
    {
        get
        {
            return _exitCommand ?? (_exitCommand = new RelayCommand(OnExit));
        }
    }
    private void OnExit(object obj)
    {
        //Application.Current.Shutdown(0);
        status_message.Text = "111111";
    }
    

    private ICommand _msgCommand;
    public ICommand MsgCommand
    {
        get
        {
            return _msgCommand ?? (_msgCommand = new RelayCommand(OnMessage));
        }
    }
    private void OnMessage(object obj)
    {
        if (obj is string)
        {
            var messageString = (string)obj;
            MessageBox.Show(messageString);
        }
    }
}
...
Рейтинг: 0 / 0
xaml cdata
    #39599791
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
у FrameworkElement, который наследует ContentControl, нужно искать через метод FindName()
https://msdn.microsoft.com/ru-ru/library/system.windows.frameworkelement.findname(v=vs.110).aspx
искать нужно начиная с корневого элемента скоупа имён. В данном случае этот скоуп начинается с ContentControl (корневого элемента) и искать нужно по имени именно в нём.
Можно элемент не только по имени найти, можно найти его в визуальном дереве.
Просто FindName ищет только в рамках своего скоупа, то есть в шаблоне данных будут свои имена, в шаблоне элемента управления свои и они могут быть одинаковыми, так как в разных скоупах не пересекаются.
...
Рейтинг: 0 / 0
xaml cdata
    #39599936
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Через поиск попробую, но не верен что это хороший вариант...
Было бы лучше: через binding или как-то думать в сторону областей видимости (если такое вообще возможно).
...
Рейтинг: 0 / 0
xaml cdata
    #39599968
microbash
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
microbashЧерез поиск попробую, но не верен что это хороший вариант...
Было бы лучше: через binding или как-то думать в сторону областей видимости (если такое вообще возможно).

Сделал через биндинг.
...
Рейтинг: 0 / 0
13 сообщений из 13, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / xaml cdata
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]