Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > WPF и Silverlight > xaml как ресурс с обработкой событий


Автор: RastaDja 30.7.2011, 13:11
   Доброго времени суток уважаемые форумчане!
   Есть у меня проект, в котором нужна генерация формы на лету, тоесть в зависимости от задачи.
   Эту задачу я думаю решить используя загрузку окна из XAML файла.

   Сейчас я описал такой класс
Код

namespace Task
{
    class Task
    {
        Window win;
        public Task()
        {
            win = new Window();
            FileStream s = new FileStream("D:\\Task.xml", FileMode.Open);
            DependencyObject rootElement = (DependencyObject)XamlReader.Load(s);
            win = (Window)rootElement;
            win.Show();
        }
    }
}

    В файл "D:\\Task.xml" записал такой код
Код

<Window x:Class="System.Windows.Window"
        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>
      <StackPanel>
        <Button Name="mbtn" Content="click me" Click="Button_Click"></Button>
      </StackPanel>
    </Grid>
    <x:Code>
      <![CDATA[
      public void Button_Click(object sender, RoutedEventArgs e)
      {
        MessageBox.Show("you clicket button");
      }
      ]]>
    </x:Code>
</Window>

   В строке (смотрите первый код) DependencyObject rootElement = (DependencyObject)XamlReader.Load(s); получаю такую ошибку:
"Не удалось создать "Click" на основе текста "Button_Click".": номер строки "7" и позиция в строке "48".

Подскажите как правильно все сделать, буду весьма признателен.

Автор: RastaDja 1.8.2011, 09:28
Судя по всему - так сделать не получится.
Надо делать, наверное, через BAML.
Подскажите, как создать BAML файл, чтоб правильно были указаны все теги, в частности x:Class.

Автор: Kefir 1.8.2011, 09:38
Почитай вот тут: http://msdn.microsoft.com/en-us/library/cc189076(v=vs.95).aspx

В частности часть:
Цитата

XAML for Load should not attempt to specify x:Class, or include any XAML-defined attributes for event handlers. Load logic cannot integrate the loaded XAML with code-behind classes at runtime. If you want to add event handlers, you must do so in code by referencing objects obtained from within the object tree structure of the Load result, and using language-specific syntax for attaching handlers (such as +=). For more information, see Events Overview for Silverlight.

Автор: RastaDja 1.8.2011, 09:52
Kefir, следуя из выше указанного, я не могу использовать код в XAML. Это очень плохо, ведь я заранее не знаю сколько и каких элементов управление будет на форме, а ещё хуже - не знаю, какие действия надо сделать при нажатии на эти элементы.
А есть ли у вас ответ на второй вопрос? 
Цитата(RastaDja @  1.8.2011,  10:28 Найти цитируемый пост)
Подскажите, как создать BAML файл

Спассибо

Автор: jonie 1.8.2011, 11:10
Цитата(RastaDja @  1.8.2011,  10:52 Найти цитируемый пост)
Kefir, следуя из выше указанного, я не могу использовать код в XAML. Это очень плохо, ведь я заранее не знаю сколько и каких элементов управление будет на форме, а ещё хуже - не знаю, какие действия надо сделать при нажатии на эти элементы.

зато есть всякие IronPython-ы ...

Автор: RastaDja 1.8.2011, 11:20
Видимо BAML можно юзать только из ресурсов. Или я не прав?
   Блин, придумал велосипед:
      1. Создать XML вида
Код

<Global>
   <XAML>
       <Grid>
            <Button Name="button1">Click me</Button>
       </Grid>
   </XAML>
   <CODE>
        <button1>                   <!-- Обработка кнопки по имени -->
              <[CDATA[
                     dim a = 100
                     msgbox a
              ]]>
        </button1>
   </CODE>
</Global>

   Но ведь это же явное извращение. Как тогда работать с листом, со списком, текст боксом?... Ума не приложу. Может кто уже столкнулся с таким заданием. Посоветуйте умное решение.

Добавлено @ 11:28
Цитата(jonie @  1.8.2011,  12:10 Найти цитируемый пост)
зато есть всякие IronPython-ы ... 

Спасибо за совет, сейчас почитаю.

Автор: Rohoss 1.8.2011, 13:47
RastaDja, я думаю подход в корню не правильный. Зачем тебе BAML, ты храни окна в сборках *.dll и их загружай.

Автор: RastaDja 1.8.2011, 14:06
Цитата(Rohoss @  1.8.2011,  14:47 Найти цитируемый пост)
Зачем тебе BAML, ты храни окна в сборках *.dll и их загружай.

Rohoss, хм. Никогда такое не делал. Можно пример?

   А вообще-то поясню что надо сделать: Нужно чтоб приложение просканировало указанную папку, из этой папки взяло имена файлов, из этих имен построило список, и вот когда мы нажмем на нужный элемент списка (тоесть выберем файл) и из этого файла построится нужный нам интерфейс. Мало того, этот интерфейс должен реагировать на юзание элементов в нем. А главное - это то, чтоб можна было таких интерфейсов создать много, и чтоб это было легко. Вот почему я выбрал модель построения, которую описал в начале темы.
   Жаль что Майкрософт не реализовала эту возможность

   Тоесть я хочу оперировать таким кодом
Код


<Window Name="MainWin" x:Class="WpfAmp.newresearch"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="newresearch" Height="320" Width="640">
    <Grid Name="ContentGrid">
        <DockPanel>
            <StackPanel DockPanel.Dock="Top">
                <WrapPanel Margin="3">
                    <Label Content="Код пробы"></Label>
                    <TextBox MinWidth="200" Name="Name"></TextBox>
                    <Label Content="Масса"></Label>
                    <TextBox MinWidth="200" Name="Rn"></TextBox>
                </WrapPanel>
                <WrapPanel Margin="3">
                    <Label Content="Название"></Label>
                    <TextBox MinWidth="200"></TextBox>
                    <Label Content="Длина" ></Label>
                    <TextBox MinWidth="200" Name="Len"></TextBox>
                </WrapPanel>
                
            </StackPanel>
            <StackPanel  DockPanel.Dock="Bottom">
                <WrapPanel>
                    <Button Content="Сохранить" Click="Clicked"></Button>
                    <Button Content="Итмена"></Button>
                </WrapPanel>
            </StackPanel>
        </DockPanel>
        
        <x:Code>
            <![CDATA[
                void Clicked(object sender, RoutedEventArgs e)
                {
                      button1.Content = "Hello World";
                      int a = Name.Text + Len.Text;
                      //сохраняем данные на диск, или другое действие
                }
             ]]>
        </x:Code>
    </Grid>
</Window>


если компиляция в длл позволит такое сделать, тогда все ок.
Относительно IronPython IronRuby, это мне напоминает MSScript, хотя может я ещё не увидел различий

Автор: hexzo 1.8.2011, 14:45
RastaDja Случайно не оно, там вроде что-то про чтение ксамла из файла.
 http://msdn.microsoft.com/en-us/library/cc189044(v=vs.95).aspx

Автор: Rohoss 1.8.2011, 14:52
RastaDja, пример может быть чуть позже. Вообще, ты ошибаешься что майкрософт такое не реализовали, смотри http://www.google.com.ua/search?sourceid=chrome&ie=UTF-8&q=m%2Canaged+extetion+framwork#hl=ru&pwst=1&sa=X&ei=OJM2TrmtGc-BhQex59H0Cg&ved=0CB8QvwUoAQ&q=managed+extension+framework&spell=1&fp=8de25be4a2448819&biw=1680&bih=949

Автор: RastaDja 1.8.2011, 16:51
Цитата(Rohoss @  1.8.2011,  15:52 Найти цитируемый пост)
Вообще, ты ошибаешься что майкрософт такое не реализовали

   Тут я имею ввиду, что майкрософт не реализовали использование тега <x:Code> при динамической загрузке XAML. А такая реализация - это очень нужная, на мой взгляд, вещь.
Цитата(Rohoss @  1.8.2011,  15:52 Найти цитируемый пост)
смотри MEF

   Смотрю. Пока ещё не понял чем это поможет мне в моей задачи. Может туплю, это факт, но всеравно не понимаю.
Цитата(Rohoss @  1.8.2011,  15:52 Найти цитируемый пост)
RastaDja, пример может быть чуть позже.

   Не сочтите за наглость - жду примера, так как искал что-то подобное - не нашол.

Автор: Rohoss 1.8.2011, 19:27
Создаём одну сборку, в которой будут вызываться окна с dll, и создаём саму dll, в которой потом создаём окно.

Автор: Rohoss 1.8.2011, 19:30
Только учти, я набросал быстро, абы как. но думаю смысл должен быть понятен 

Автор: RastaDja 1.8.2011, 22:58
Цитата(hexzo @  1.8.2011,  15:45 Найти цитируемый пост)
RastaDja Случайно не оно, там вроде что-то про чтение ксамла из файла.
 http://msdn.microsoft.com/en-us/library/cc...4(v=vs.95).aspx

это я уже сделал, в топике мой код аналогичен.

Rohoss спасибо за сборку (+). Утром на Работе посмотрю. Если будут вопросы обращусь ещё))

Автор: RastaDja 2.8.2011, 08:41
Rohoss, ваш пример хороший, но он действует внутри сборки. Как подключать модули не зная имен типов внутри модуля - это не понятно. К тому-же, не хочется перекомпилировать сборку каждый раз, и под каждого закажкика, когда нужно добавить одно или два окна. Все-таки хочится делать все попроще. Раньше для этого была написано скрипт машина, с прописаными заранее функциями и т.д.
   Сейчас ее возможностей маловато, хочется писать программы под современный интерфейс используя WPF, в тоже время хочется быстро редактировать окно, или часть окна (некоторые части будут загружатся внутрь окна главного приложения). Хотелось бы открыть блокнот, набрать за 30-40минут код, и вуа-ля. Как-то не хочется велосипедить со скрипт машиной, не важно что это Shell, Python, VBScript или что-то другое.. Но видимо придется.
   Ваша идея действительно хорошая, но как это сделать для любой ДЛЛ, не только из сборки, и к тому-же - это уже скомпилированный файл, который нет возможности поправить (заменить int a=2 На int a=3 например, не получится).

Автор: Rohoss 2.8.2011, 10:00
Цитата(RastaDja @  2.8.2011,  08:41 Найти цитируемый пост)
Rohoss, ваш пример хороший, но он действует внутри сборки. Как подключать модули не зная имен типов внутри модуля - это не понятно.

Тут тебе пригодится MEF. Как появится время приведу пример.

Цитата(RastaDja @  2.8.2011,  08:41 Найти цитируемый пост)
К тому-же, не хочется перекомпилировать сборку каждый раз, и под каждого закажкика, когда нужно добавить одно или два окна. 

Ну не собирая всё равно в текстовых файлах ничего не сделаешь. Или попробуй через IronPython, там вроде такое можно делать.

Автор: RastaDja 2.8.2011, 11:04
Цитата(Rohoss @  2.8.2011,  11:00 Найти цитируемый пост)
Или попробуй через IronPython, там вроде такое можно делать. 

   Мне кажется - это один из лучших вариантов. Придется затратить время на изучение. Единственно - что не понятно - писать приложение на питоне, или внедрить скрипт машину внутрь приложения? Так, как не сталкивался с этим, тяжело представить, но кажется это оптимально, например, когда программист приедет сразу в компанию закажчика, и поправит (новый напишет) код, не имея никаких средств разработки.
   Если вы использовали IronPython подскажите с чего начать, или поделитесь ссылками.
   Спасибо

Добавлено через 1 минуту и 37 секунд
Цитата(Rohoss @  2.8.2011,  11:00 Найти цитируемый пост)
Тут тебе пригодится MEF. Как появится время приведу пример.

   Да, я не против посмотреть на это, хотя пока не разобрался что за технология

Автор: Kefir 2.8.2011, 20:41
Если хочешь красоты и без Visual Studio, то пишешь маленькую утилиту, которая берет на вход xaml + cs и даёт на выходе dll. А внутри динамически эти dll-ки подгружает. Хоть через MEF, хоть сам напиши. Всего делов. Туториалы MEF есть в свободном доступе на MSDN, туториалов по самостоятельной подгрузке dll в интернете как грязи (напиши хотя бы plugin architecture или load dll c# в гугле).

Если не хочешь ничего компилировать - ищи скриптовый язык, который под это заточен.

Автор: RastaDja 3.8.2011, 14:23
Цитата(Kefir @  2.8.2011,  21:41 Найти цитируемый пост)
Если не хочешь ничего компилировать - ищи скриптовый язык, который под это заточен. 

   Посоветовали PowerShell. В принципе выглядит неплохо. Структура файла получается такого типа
Код

<?xml version="1.0" encoding="utf-8" ?> 
   <construktor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xaml>
         <Window Name="MainWin" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="System.Windows.Window" Title="newresearch" Height="320" Width="640">
            <Grid Name="ContentGrid">
               <StackPanel>
                  <Button Name="button1">Действие1</Button>
                  <Button Name="button2">Действие2</Button>
               </StackPanel>
            </Grid>
         </Window>
      </xaml> 
      <code>
         <script Name="button1_Click">
            $App = New-Object -ComObject DrApp.Application
            $App.Show
         </Script> 
      </code>
  </construktor>


внутри класса C# парсим наше окно от корня, и подписываем наши элементы на события.
Ну и пример обработки
Код

//  общий обработчик для всех кнопок
private void Buttons_Click(object sender, RoutedEventArgs e)
{
   Button refButton = (Button)sender;
   string FuncName = String.Format("{0}_{1}", refButton.Name, "Click");
   Pipeline pl = runspace.CreatePipeline(FuncName);
   try
   {
      pl.Invoke();
   }
   catch (Exception ex)
   {
      MessageBox.Show(ex.Message);
   }
}

   Как то так. Еще раз спасибо всем, кто принял участие в обсуждении.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)