? Класс CSharpCodeProvider. Возможности применения

Класс CSharpCodeProvider. Возможности применения

Аннотация: Данная статья не описание разработки конкретной программы, а пособие по динамическому созданию одной программы из другой.

  • 4. Литература

    Класс CSharpCodeProvider обычно рассматривают в аспекте динамической компиляции и загрузки кода, когда требуется внесение изменений в функциональность приложений без их перекомпиляции. Как правило, это разработка программ, способных обрабатывать скрипты (и не только написанные на С#, но и скрипты JS, VB). Однако, куда более интересной, является возможность использования класса для формирования полнофункциональных приложений по шаблонам с динамически задаваемыми на этапе компиляции характеристиками.


    В начало

    Параграф 1. Постановка задачи и разработка шаблона программы (программа Slave)

    Создадим приложение, которое позволяет создавать фотоальбомы, оформленные как Windows программы. Причем, каждый фотоальбом должен иметь свою иконку для exe файла, свою иконку для приложения, заставку при старте и ряд других настроек. Иначе, будем создавать программы Master - для создания программ-фотоальбомов и Slave - собственно шаблон программы для фотоальбомов.

    На начальном этапе создадим простейший прообраз будущей программы фотоальбома (шаблон Slave программы). Сформируем проект Windows решения с именем SlideMakerX (X - текущий рабочий номер). Поместим на форму контролы Button, TextBox и PictureBox (Рис.1.). В дальнейшем мы изменим набор контролов, но на первоначальном этапе они нам необходимы для понимания процессов создания файлов решения и принятых кодовых конструкций, которые могут быть обработаны классом CSharpCodeProvider.

    codeprovider001.gif

    Рис.1. Проект решения 1

    Начнем вносить изменения в структуру проекта решения:

    • Найдем в Solutation Explorer файл AssemblyInfo.cs. и полностью перенесем его в начало файла Form1.cs. Причина - класс CSharpCodeProvider "не терпит" директивы Using, разбросанные по нескольким файлам.

    • Аналогично поступим и с классом Program из файла Program.cs. Однако, расположим его содержимое обязательно ниже public partial class Form1 - иначе класс CSharpCodeProvider откажется компилировать наш проект.

    • Удалим из проекта файл Form1.resx - он обрабатывается исключительно внутренними механизмами Visual Studio. Удаление файла приведет к тому, что мы не сможем установить некоторые параметры для всего приложения (например иконку), и, как результат, возникнут некоторые особенности при работе с ресурсами, о которых речь пойдет ниже.

    • Так как приложение должно иметь иконку и начальную заставку, то поместим их в ресурс. Для этого дважды кликнем в Solutation Explorer по файлу Resources.resx и на вкладке Resources.resx, воспользовавшись закладкой Add Resource, добавим к ресурсам одну иконку и одну картиночку в формате jpg (Рис.2.). Обратим внимание, что в решении появилась новая папка Resources, содержимое которой являются два добавленных в ресурс файла.

    • Мы могли бы удалить из проекта решения узлы Settings, но они пока требуются, как и узлы Resources.resx и Resources.Designer.cs для параллельной компиляции и отладки решения в Visual Studio.

    codeprovider002.gif

    Рис.2. Добавление изображений в ресурс

    Приведем код файла Form1.cs, который получился у нас в результате объединения трех файлов. Код в конструкторе будет пояснен ниже.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    using System.Resources;
    //////////////////////////////////////////////////////////////////
    //Эта часть перенесена из файла AssemblyInfo.cs
    //////////////////////////////////////////////////////////////////
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    [assembly: AssemblyTitle("SlideMaker2")]
    [assembly: AssemblyDescription("")]
    [assembly: AssemblyConfiguration("")]
    [assembly: AssemblyCompany("wlad")]
    [assembly: AssemblyProduct("SlideMaker2")]
    [assembly: AssemblyCopyright("Copyright c wlad 2007")]
    [assembly: AssemblyTrademark("")]
    [assembly: AssemblyCulture("")]
    [assembly: ComVisible(false)]
    [assembly: Guid("503656d7-b907-4d31-a09b-45a3016f0d4f")]
    [assembly: AssemblyVersion("1.0.0.0")]
    [assembly: AssemblyFileVersion("1.0.0.0")]
    
    namespace SlideMaker2
    {
     //////////////////////////////////////////////////////////////////
     //Класс partial Form1 (файл Form1.cs)
     //////////////////////////////////////////////////////////////////
     public partial class Form1 : Form
     {
      public Form1()
      {
       InitializeComponent();  
       /////////////////////////////////////////////////////////////////      
       //Пояснение этой части кода в конструкторе будет дано ниже
       /////////////////////////////////////////////////////////////////
       string[] sRes = 
       System.Reflection.Assembly.
            GetExecutingAssembly().GetManifestResourceNames();
       int viI = -1;
       int viJ = -1;
       for (int i = 0; i < sRes.Length; i++)
       {
        textBox1.Text += sRes[i].ToString() + Environment.NewLine;
        if (sRes[i].ToUpper().Contains("A1"))
        {
         viI = i;
        }
        if (sRes[i].ToUpper().Contains("A0"))
        {
         viJ = i;
        }
       }
       if (viI != -1)
       {
        using (Stream theResource = System.Reflection.Assembly.
              GetExecutingAssembly().GetManifestResourceStream(sRes[viI]))
        { 
         this.Icon = new Icon(theResource);
        }
       }
       else
       {
        Icon = Properties.Resources.a1;
       }
       if (viJ != -1)
       {
        using (Stream theResource 
           = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(sRes[viJ]))
        {
         pictureBox1.Image = Image.FromStream(theResource); 
        }
       }
       else
       {
        pictureBox1.Image = Properties.Resources.a0;
       }       
      }
      //////////////////////////////////////////////////////////////////
      //Для показа того, что можно что-то делать в обработчиках событий
      //////////////////////////////////////////////////////////////////
      private void button1_Click(object sender, EventArgs e)
      {
       Text = "Hello World C#";
      } 
     }
     //////////////////////////////////////////////////////////////////
     //Это часть кода из файла Programm.cs
     //////////////////////////////////////////////////////////////////
     static class Program
     {            
      [STAThread]
      static void Main()
      {
       Application.EnableVisualStyles();
       Application.SetCompatibleTextRenderingDefault(false);
       Application.Run(new Form1());
      }
     }
    }
    

    Откомпилируем и выполним решение. Мы увидим, что наше Windows приложение имеет все то, что мы от него потребовали на первом этапе (Рис.3.).

    codeprovider003.gif

    Рис.3. Результат выполнения кода

    Поясним код приведенный в конструкторе:

    1. Следующая конструкция позволяет нам получить имена всех ресурсов, которые есть в приложении в виде массива строк.

    string[] sRes = 
       System.Reflection.Assembly.
            GetExecutingAssembly().GetManifestResourceNames();
    

    2. Не смотря на наличие нескольких файлов, так или иначе связанных с ресурсами, в приложении есть только один общий ресурс, а все остальные файлы только обеспечивают взаимодействие приложения с ресурсом:

    SlideMaker2.Properties.Resources.resources
    

    3. В файле Resources.Designer.cs можно видеть механизм доступа к объектам ресурса в пространстве SlideMaker2.Properties.Resources:

    internal static System.Drawing.Bitmap a0 
    {
     get 
     {
      object obj = ResourceManager.GetObject("a0", resourceCulture);
      return ((System.Drawing.Bitmap)(obj));
     }
    }
    internal static System.Drawing.Icon a1 
    {
     get 
     {
      object obj = ResourceManager.GetObject("a1", resourceCulture);
      return ((System.Drawing.Icon)(obj));
     }
    }
    

    4. В приведенном примере, отображение иконки и заставки выполнено с использованием приведенных механизмов доступа:

    Icon = Properties.Resources.a1;
    pictureBox1.Image = Properties.Resources.a0;
    

    5. Остальной код в конструкторе рассчитан на то, что у нас в приложении после компиляции будут ресурсы, содержащие имена a0 и a1 (см.далее).


    В начало

    Параграф 2. Программная компиляция шаблона программы (программа Master)

    Создадим новое приложение, которое будет выполнять роль программы-Master, компилировать программный код программы Slave (собственно альбома) и создавать готовый ее exe файл.

    Сформируем обычный проект Windows решения с именем CreateProgramm (Рис.4.). Поместим на форму три контрола Button, два контрола PictureBox , контролы TextBox, Label, FileListBox и OpenFileDialog.

    codeprovider004.gif

    Рис.4. Проект решения 2

    В дальнейшем мы изменим набор контролов в соответствии с новыми потребностями. Далее, создадим обработчики нажатия кнопок и запишем базовый код, который пока не включает собственно компиляцию Slave кода:

    public partial class Form1 : Form
    {
     string sPathIcon = string.Empty;
     string sBackGround = string.Empty;
     string sWorkDirectory = string.Empty;
     public Form1()
     {
      InitializeComponent();
      //Рабочая директория проекта
      sWorkDirectory=Directory.GetCurrentDirectory();
     }
     //Выбор иконки для приложения Slave программы
     private void button2_Click(object sender, EventArgs e)
     {
      openFileDialog1.FileName = "";
      openFileDialog1.Filter = "ico файлы (*.ico)|*.ico";
      if (openFileDialog1.ShowDialog() == DialogResult.OK)
      {
       sPathIcon = openFileDialog1.FileName;
       pictureBox1.Image = Image.FromFile(sPathIcon);
       File.Copy(sPathIcon, sWorkDirectory + @"\Programm\a1.ico",true);
      }
     }
     //Выбор заставки для Slave программы
     private void button3_Click(object sender, EventArgs e)
     {
      openFileDialog1.FileName = "";
      openFileDialog1.Filter = "jpg файлы (*.jpg)|*.jpg|jpeg файлы (*.jpeg)|*.jpeg";
      if (openFileDialog1.ShowDialog() == DialogResult.OK)
      {
       sBackGround = openFileDialog1.FileName;
       pictureBox2.Image = Image.FromFile(sBackGround);
       pictureBox2.Image.Save(sWorkDirectory + 
        @"\Programm\a0.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
      }
     }
    
     //В button1_Click будем выполнять динамическую компиляцию
     private void button1_Click(object sender, EventArgs e)
     {   
      //Требование задать иконку, заставку и имя программы
      if (textBox2.Text.Trim() == "")
      {
       MessageBox.Show("Не задано имя альбома. Введите его в соответствующем поле!", 
        "Имя", MessageBoxButtons.OK, MessageBoxIcon.Question);
       return;
      }
      if (sPathIcon == string.Empty || sBackGround == string.Empty)
      {
       MessageBox.Show("Не выбрана иконка или заставка для приложения.", 
        @"Иконка\заставка", MessageBoxButtons.OK, MessageBoxIcon.Question);
       return;
      }
    
      //Далее пойдет код динамической компиляции
      ..............................
    }
    

    Данный код не представляет интереса. Он всего лишь позволяет выбрать и сохранить требуемые параметры. Для сохранения параметров создадим папку Programm в рабочей директории данного приложения (у меня на период отладки это C:\SamplesC#\CreateProgramm\bin\Debug\Programm\).

    Отметим также, что мы можем выбирать рисунок для заставки любого формата. О работе с различными форматами рисунков Вы можете посмотреть здесь. Примерный вид программы показан на Рис.5.

    codeprovider005.gif

    Рис.5. Выбор параметров

    Все, что нам понадобится для компиляции от кода Slave программы - это два файла Form1.cs и Form1.Designer.cs, которые мы скопируем в созданную папку Programm. На начало компиляции там будут, как отмечено выше, и файлы иконки и заставки. Рассмотрим код выполняющий компиляцию (все пояснения приведены в коде):

    //Прежде всего пространства имен, которые необходимы:
    using System;
    using System.Collections.Generic;
    using System.CodeDom.Compiler;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using Microsoft.CSharp;
    using System.IO;
    
    ......
    
    //А этот код добавляем в обработчик button1_Click
    
    //Создаем экземпляр компилятора C# кода
    using (CSharpCodeProvider code = new CSharpCodeProvider())
    {
     //Создаем экземпляр класса параметров для компилятора
     CompilerParameters compileparam = new CompilerParameters();
     //Добавляем основные опции компилятора: target - целевой файл - winexe;
     //win32icon - наличие иконки для exe файла (не приложения!!), в качестве иконки 
     //выберем тот же файл, что мы собирались сделать иконкой приложения sPathIcon;
     //res - ресурсы приложения - мы добавили выбранные нами файлы a0.jpg и a1.ico
     compileparam.CompilerOptions = "/target:winexe" + " " + "/win32icon:" + "\"" + sPathIcon + "\" "
          + "/res:" + "\"" + sWorkDirectory + @"\Programm\a0.jpg" + "\" "                
          + "/res:" + "\"" + sWorkDirectory + @"\Programm\a1.ico" + "\" ";
     //Параметр GenerateExecutable определяет тип создаваемого приложения 
     //false -  DLL, true - exe файл
     compileparam.GenerateExecutable = true;
     //Полезно для отладки
     compileparam.IncludeDebugInformation = false;
     //Имя выходного файла
     compileparam.OutputAssembly = @"c:\"+textBox2.Text.Trim()+".exe";
     //Сохранять ли на диске созданный файл или выполнить в памяти
     compileparam.GenerateInMemory = false;
     //Добавление библиотек для компиляции, которые не являются 
     //обязательными для Slave программы
     compileparam.ReferencedAssemblies.Add("System.dll");                
     compileparam.ReferencedAssemblies.Add("System.Data.dll");
     compileparam.ReferencedAssemblies.Add("System.Deployment.dll");
     compileparam.ReferencedAssemblies.Add("System.Drawing.dll");
     compileparam.ReferencedAssemblies.Add("System.Windows.Forms.dll");
     compileparam.ReferencedAssemblies.Add("System.Xml.dll");
     //О том как работать с предупреждениями
     compileparam.TreatWarningsAsErrors = false;
     //И собственно компиляция
     CompilerResults compilerresults = code.CompileAssemblyFromFile(compileparam,
     new string [] 
     { 
      sWorkDirectory + @"\Programm\Form1.cs",
      sWorkDirectory + @"\Programm\Form1.Designer.cs"
     });
     //Осталось посмотреть ошибки, если они были
     if (compilerresults.Errors.Count > 0)
     {
      Text = "Error: "+compilerresults.Errors[0].ErrorText;
      if(compilerresults.Errors.Count > 1)
        Text += ";" + compilerresults.Errors[0].ErrorText;
      }
      else
      {
       Text = "The compilation is executed successfully";
      }
    }
    

    Найдем скомпилированный файл C:\a1.exe и исследуем его:

    • Файл имеет иконку.

    • Приложение при запуске имеет иконку и отображает картинку, которая была помещена в ресурс (Рис.6.)

      codeprovider006.gif

      Рис.6. Выполнение целевого приложения

    • Ресурс в приложении представлен двумя объектами a0.jpg и a1.ico. Ветвь извлечения ресурса в Slave коде, соответственно через поток, а не прямое обращение:

      public Form1()
      {
       InitializeComponent();            
       string[] sRes = 
        System.Reflection.Assembly.GetExecutingAssembly().
                                   GetManifestResourceNames();
       int viI = -1;
       int viJ = -1;
       for (int i = 0; i < sRes.Length; i++)
       {
        textBox1.Text += sRes[i].ToString() + Environment.NewLine;
        if (sRes[i].ToUpper().Contains("A1"))
        {
         viI = i;
        }
        if (sRes[i].ToUpper().Contains("A0"))
        {
         viJ = i;
        }
       }
       if (viI != -1)
       {
        using (Stream theResource = 
           System.Reflection.Assembly.GetExecutingAssembly().
                           GetManifestResourceStream(sRes[viI]))
        {
         this.Icon = new Icon(theResource);
        }
       }
       else
       {
        //Строка должна быть закомментирована - такого ресурса нет
        //Icon = Properties.Resources.a1;
       }
       if (viJ != -1)
       {
        using (Stream theResource 
             = System.Reflection.Assembly.
                 GetExecutingAssembly().GetManifestResourceStream(sRes[viJ]))
        {
         pictureBox1.Image = Image.FromStream(theResource); 
        }
       }
       else
       {
        //Строка должна быть закомментирована - такого ресурса нет
        //pictureBox1.Image = Properties.Resources.a0;
       }       
      }
      

    Отметим, что возможно загрузить файлы Form1.cs и Form1.Designer.cs в TextBox, то вместо конструкции new string[] можно использовать textBox1.Text (на этом основывается возможность выполнения скриптов из приложений), то есть:

    //Данный код
    CompilerResults compilerresults = code.CompileAssemblyFromFile(compileparam,
    new string [] 
     { 
      sWorkDirectory + @"\Programm\Form1.cs",
      sWorkDirectory + @"\Programm\Form1.Designer.cs"
     });
    //Равноценен коду
    CompilerResults compilerresults = code.CompileAssemblyFromFile(compileparam,
    terextBox1.Text);
    


    В начало

    Параграф 3. О возможности использования коллекции EmbeddedResources для добавления ресурсов

    В приведенном выше коде мы определили каждый ресурс отдельно при задании опций компиляции (CompilerOptions). Это не совсем удобно. Другим путем является использование свойства класса CompilerParameters EmbeddedResources, которое дает возможность получить StringCollection ресурсов и, используя метод Add класса StringCollection, добавить пути к каждому ресурсу отдельно. При последующей компиляции ресурс становится частью тела целевого ехе файла.

    Внесем изменения в программу Master. Установим свойства MultiSelect контрола openFileDialog1 и MultiLine контрола filelistBox1 в true и добавим контрол Button. В обработчике нажатия этой кнопки создадим код формирования списка фотографий. Кроме того объявим переменную viCountNumPhoto для учета количества фотографий, помещенных в список.

    private void button4_Click(object sender, EventArgs e)
    {
     openFileDialog1.FileName = "";
     openFileDialog1.Filter = "jpg файлы (*.jpg)|*.jpg|jpeg файлы (*.jpeg)|*.jpeg";
     if(viCountNumPhoto == 0)  filelistBox1.Items.Clear();
     if (openFileDialog1.ShowDialog()==DialogResult.OK)
     {
      for (int i = 0; i < openFileDialog1.FileNames.Length; i++)
      {
       viCountNumPhoto++;
       filelistBox1.Items.Add(openFileDialog1.FileNames[i]); 
      }
     }
    }
    

    При неудачном формировании списка можно предусмотреть кнопку его очистки и ряд других сервисных функций. Можно предусмотреть загрузку фото и картинок в разных форматах и преобразование форматов и т.д. и т.п. Иначе, на данном этапе открывается широкое поле для творчества, но, так как это не является нашей целью, останавливаться на этом не будем.

    И так, на данный момент в filelistBox1 унас список файлов, которые мы должны добавить к тем, что уже добавляются в ресурс. Эту задачу выполнит следующий код, помещенный в обработчик нажатия кнопки 1:

    //Копируем файлы с оригинальными именами
    for (int i = 1; i <= filelistBox1.Items.Count; i++)
    {
     File.Copy((string)filelistBox1.Items[i-1],
      sWorkDirectory + @"\Programm\b" + 
      Convert.ToString(i) + ".jpg", true);
    }
    //Добавряем список в ресурс
    for (int i = 1; i <= filelistBox1.Items.Count; i++)
    {
     compileparam.EmbeddedResources.Add(sWorkDirectory + 
             @"\Programm\b" + Convert.ToString(i) + ".jpg");
    }
    

    Выполнив код на данном этапе мы можем убедиться после запуска программы Slave, что все ресурсы доступны в программе (Рис.7.).

    codeprovider007.gif

    Рис.7. Добавление файлов фотографий в ресурс

    Как обеспечить доступ к ресурсу, мы уже знаем, поэтому далее приводим только код вывода фото в PictureBox1 программы Slave.

    private int viNumPhoto=1;
    .....
    
    private void button1_Click(object sender, EventArgs e)
    {
     Text = "Просмотр фото";
     try
     {
      pictureBox1.Image = 
       Image.FromStream(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream
           ("b" + Convert.ToString(viNumPhoto) + ".jpg"));
      textBox1.Text = "b" + Convert.ToString(viNumPhoto) + ".jpg";
      viNumPhoto++;
     }
     catch (Exception)
     {
      textBox1.Text = "На новый круг";
      viNumPhoto=1;
     }
    }
    

    Вновь перенесем файлы Form1.cs и Form1.Designer.cs в директорию Programm и выполним программу Master. В созданной мастером программе мы теперь можем просматривать те фото, которые помещены в ресурс, нажимая кнопку 1.


    В начало

    Параграф 4. О возможности передачи параметров между программами Master/Slave

    Расширим поставленную задачу. Пусть нам требуется задавать и отображать имя альбома и менять фон панели программы. На данном этапе можно потребовать много других настроек, нас же интересует сам принцип выполнения передачи параметров. Передачу параметров будем выполнять, как и ранее, через коллекцию EmbeddedResources (ресурсы) с использованием XML файла. XML файл будет включать данные класса параметров настройки для Slave программы или точнее сериализованное XML представление класса настроек.

    Для выполнения задачи:

    • Добавим пространство имен в программу Master: using System.Xml.Serialization;

    • Создадим класс для хранения параметров, поместив его в пространство имен CreateProgramm, как и любой метод или функцию:

      [Serializable]
      public class MyProgrammSettings
      {
       string name;
       int colorA;
       int colorR;
       int colorG;
       int colorB;
       public string Name
       {
        get { return name; }
        set { name = value; }
       }
       public int ColorA
       {
        get { return colorA; }
        set { colorA = value; }
       }
       public int ColorR
       {
        get { return colorR; }
        set { colorR = value; }
       }
       public int ColorG
       {
        get { return colorG; }
        set { colorG = value; }
       }
       public int ColorB
       {
        get { return colorB; }
        set { colorB = value; }
       }
      }
      
    • В программе Master добавим кнопку выбора для фона программы (контрол Button), контрол ColorDialog и контрол Panel для отображения выбранного цвета (Рис.8.). Имя фотоальбома и имя exe файла, для простоты, примем одинаковыми.

      codeprovider008.gif

      Рис.8. Проект решения

    • Создадим объект класса MyProgrammSettings:

      private MyProgrammSettings myPrSettings = new MyProgrammSettings();
      
    • Код выбора цвета запишем как:

      private void button5_Click(object sender, EventArgs e)
      {
       if (colorDialog1.ShowDialog() == DialogResult.OK)
       {
        panel1.BackColor  = colorDialog1.Color;
       }
      }
      
    • В обработчике нажатия кнопки 1 добавим код для заполнения класса значениями параметров, сериализации его в XML файл и добавления в ресурс программы Slave:

      myPrSettings.ColorA = panel1.BackColor.A;
      myPrSettings.ColorR = panel1.BackColor.R;
      myPrSettings.ColorG = panel1.BackColor.G;
      myPrSettings.ColorB = panel1.BackColor.B;
      myPrSettings.Name = textBox2.Text.Trim();
      Stream stream = File.Open(sWorkDirectory 
                 + @"\Programm\progsettings.xml", FileMode.Create);
      XmlSerializer xmlSerializer 
            = new XmlSerializer(typeof(MyProgrammSettings));
      xmlSerializer.Serialize(stream, myPrSettings);
      stream.Close();
      compileparam.EmbeddedResources.Add(sWorkDirectory 
                      + @"\Programm\progsettings.xml");
      

    Если откомпилировать и выполнить программу Master, то в созданной программе Slave мы найдем ресурс progsettings.xml (Рис.9.).

    codeprovider009.gif

    Рис.9. Результат выполнения кода

    Осталось забрать из ресурса настройки. Для этого, в программе Slave:

    • Повторим класс настроек MyProgrammSettings, поместив его в Form1.cs в класс partial class Form1:

      [Serializable]
      public class MyProgrammSettings
      {
       string name;
       int colorA;
       int colorR;
       int colorG;
       int colorB;
       public string Name
       {
        get { return name; }
        set { name = value; }
       }
       public int ColorA
       {
        get { return colorA; }
        set { colorA = value; }
       }
       public int ColorR
       {
        get { return colorR; }
        set { colorR = value; }
       }
       public int ColorG
       {
        get { return colorG; }
        set { colorG = value; }
       }
       public int ColorB
       {
        get { return colorB; }
        set { colorB = value; }
       }
      }
      
    • Создадим объект класса MyProgrammSettings:

      private MyProgrammSettings myPrSettings = new MyProgrammSettings();
      
    • Добавим пространство имен using System.Xml.Serialization;

    • В конструкторе Form1 поместим код:

      XmlSerializer xmlSerializer 
       = new XmlSerializer(typeof(MyProgrammSettings));
      Stream stream 
       = System.Reflection.Assembly.GetExecutingAssembly().
                GetManifestResourceStream("progsettings.xml");
      myPrSettings 
       = xmlSerializer.Deserialize(stream) as MyProgrammSettings;
      stream.Close();
      this.BackColor  = Color.FromArgb(myPrSettings.ColorA,
          myPrSettings.ColorR, myPrSettings.ColorG, myPrSettings.ColorB);
      Text = myPrSettings.Name;
      

    Результат работы показан на Рис.10.

    codeprovider010.gif

    Рис.10. Программы Master/Slave

    На этом мы заканчиваем рассмотрение темы. В отношении технологии взаимодействия программ Master/Slave при динамической компиляции Slave программы, приведенный подход является универсальным. Аналогично можно создавать музыкальные и другие альбомы и любые приложения, функциональность которых требуется несколько изменить по отношению к функциональности базового шаблона. Задача будет заключаться лишь в том, как добавить в ресурс, как извлечь из ресурса данные, как преобразовать их в требуемый формат и как использовать.


    В начало

    Литература:


    В начало

    Молчанов Владислав 5.10.2007г.

    Еcли Вы пришли с поискового сервера - посетите мою главную страничку

    На главной странице Вы найдете программы комплекса Veles - программы для автолюбителей, программы из раздела графика - программы для работы с фото, сделанными цифровым фотоаппаратом, программу Bricks - игрушку для детей и взрослых, программу записную книжку, программу TellMe - говорящий Русско-Английский разговорник - программу для тех, кто собирается погостить за бугром или повысить свои знания в английском, теоретический материал по программированию в среде Borland C++ Builder, C# (Windows приложения и ASP.Net Web сайты).

    В начало страницы

    К началу теоретического материала по C#

    На главную страницу


  • Сайт управляется системой uCoz