Введение в программирование на C# 2.0

GDI+

Разбить на страницы
Показывать лекцию целиком

GDI+ - это набор программных средств, которые используются в .NET.

GDI+ позволяют создателям приложений выводить данные на экран или на принтер без необходимости обеспечивать работу с определенными типами устройств отображения. Для отображения информации программисту достаточно вызывать нужные методы классов GDI+. При этом автоматически учитываются типы определенных устройств и выполняются вызовы соответствующих драйверов.

Graphics

Класс, который ИНКАПСУЛИРУЕТ поверхность рисования GDI+. Для этого класса не определен ни один конструктор. Видимо, успех в деле ручного конструирования инкапсулятора поверхностей рисования (еще вопрос, сколько разновидностей таких поверхностей) представляется проблематичным.

Конкретный объект – представитель класса Graphics предоставляется в виде ссылки методами-обработчиками событий либо создается в ходе выполнения ряда методов применительно к конкретным объектам, обладающим "поверхностями рисования" (клиентская область формы, кнопки, панели, битовая матрица):

Bitmap bmp;
Pen greedPen;
:::::
greedPen = new Pen(Color.FromArgb(50, 0, 0, 255), 1);
// Новая битовая карта под новый размер клиентской области формы.
bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
Graphics gr = Graphics.FromImage(bmp);
gr.DrawLine(this.greedPen, 0, 0, 100, 100);
gr.Dispose();

Ниже представлен список членов класса.

Clip Получает или задает объект Region, ограничивающий область рисования данного объекта Graphics
ClipBounds Получает структуру RectangleF, которая заключает в себе вырезанную область данного объекта Graphics
CompositingMode Получает значение, задающее порядок рисования сложных изображений в данном объекте Graphics
CompositingQuality Получает или задает качество отображения сложных изображений, которые выводятся в данном объекте Graphics
DpiX Получает горизонтальное разрешение данного объекта Graphics
DpiY Получает вертикальное разрешение данного объекта Graphics
InterpolationMode Получает или задает режим вставки, связанный с данным объектом Graphics
IsClipEmpty Получает значение, которое указывает, является ли вырезанная область данного объекта Graphics пустой
IsVisibleClipEmpty Получает значение, которое указывает, является ли видимая вырезанная область данного объекта Graphics пустой
PageScale Получает или задает масштабирование между универсальными единицами и единицами страницы для данного объекта Graphics
PageUnit Получает или задает единицу измерения для координат страницы данного объекта Graphics
PixelOffsetMode Получает или задает значение, которое задает порядок смещения точек во время отображения данного объекта Graphics
RenderingOrigin Получает или задает исходное заполнение данного объекта Graphics для сглаживания цветовых переходов и для штриховки
SmoothingMode Получает или задает качество заполнения для данного объекта Graphics
TextContrast Получает или задает значение коррекции яркости для отображения текста
TextRenderingHint Получает или задает режим заполнения для текста, связанного с данным объектом Graphics
Transform Получает или задает универсальное преобразование для данного объекта Graphics
VisibleClipBounds Получает или задает рабочий прямоугольник видимой вырезанной области данного объекта Graphics
Открытые методы
AddMetafileComment Добавляет комментарий к текущему объекту Metafile
BeginContainer Перегружен. Сохраняет графический контейнер, содержащий текущее состояние данного объекта Graphics, а затем открывает и использует новый графический контейнер
Clear Очищает всю поверхность рисования и выполняет заливку поверхности указанным цветом фона
CreateObjRef Создает объект, который содержит всю необходимую информацию для создания прокси-сервера, используемого для коммуникации с удаленными объектами
Dispose Освобождает все ресурсы, используемые данным объектом Graphics
DrawArc Перегружен. Рисует дугу, которая является частью эллипса, заданного парой координат, шириной и высотой
DrawBezier Перегружен. Строит кривую Безье, определяемую четырьмя структурами Point
DrawBeziers Перегружен. Формирует набор кривых Безье из массива структур Point
DrawClosedCurve Перегружен. Строит замкнутую фундаментальную кривую, определяемую массивом структур Point
DrawCurve Перегружен. Строит замкнутую фундаментальную кривую через точки указанного массива структур Point
DrawEllipse Перегружен. Формирует эллипс, который определяется ограничивающим прямоугольником, заданным с помощью пары координат — ширины и высоты
DrawIcon Перегружен. Формирует изображение, которое представлено указанным объектом Icon, расположенным по указанным координатам
DrawIconUnstretched Формирует изображение, представленное указанным объектом Icon, не масштабируя его
DrawImage Перегружен. Рисует заданный объект Image в заданном месте, используя исходный размер
DrawImageUnscaled Перегружен. Рисует заданное изображение, используя его исходный фактический размер, в расположении, заданном парой координат
DrawLine Перегружен. Проводит линию, соединяющую две точки, определенные парами координат
DrawLines Перегружен. Формирует набор сегментов линии, которые соединяют массив структур Point
DrawPath Рисует объект GraphicsPath
DrawPie Перегружен. Рисует сектор, определенный эллипсом, который задан парой координат, шириной, высотой и двумя радиальными линиями
DrawPolygon Перегружен. Рисует многоугольник, определяемый массивом структур Point
DrawRectangle Перегружен. Рисует прямоугольник, который определен парой координат, шириной и высотой
DrawRectangles Перегружен. Рисует набор прямоугольников, определяемых структурой Rectangle
DrawString Перегружен. Создает текстовую строку в заданном месте с указанными объектами Brush и Font
EndContainer Закрывает текущий графический контейнер и восстанавливает состояние данного объекта Graphics, которое было сохранено при вызове метода BeginContainer
EnumerateMetafile Перегружен. Отправляет записи указанного объекта Metafile по отдельности методу обратного вызова, который отображает их в заданной точке
Equals Перегружен. Определяет, равны ли два экземпляра Object
ExcludeClip Перегружен. Обновляет вырезанную область данного объекта Graphics, чтобы исключить из нее часть, определенную структурой Rectangle
FillClosedCurve Перегружен. Заполняет замкнутую фундаментальную кривую, определяемую массивом структур Point
FillEllipse Перегружен. Заполняет внутреннюю часть эллипса, который определяется ограничивающим прямоугольником, заданным с помощью пары координат — ширины и высоты
FillPath Заполняет внутреннюю часть объекта GraphicsPath
FillPie Перегружен. Заполняет внутреннюю часть сектора, определенного эллипсом, который задан парой координат, шириной, высотой и двумя радиальными линиями
FillPolygon Перегружен. Заполняет внутреннюю часть многоугольника, определенного массивом точек, заданных структурами Point
FillRectangle Перегружен. Заполняет внутреннюю часть прямоугольника, который определен парой координат, шириной и высотой
FillRectangles Перегружен. Заполняет внутреннюю часть набора прямоугольников, определяемого структурами Rectangle
FillRegion Заполняет внутреннюю часть объекта Region
Flush Перегружен. Вызывает принудительное выполнение всех отложенных графических операций и немедленно возвращается, не дожидаясь их окончания
FromHdc Статический. Перегружен. Создает новый объект Graphics из указанного дескриптора для контекста устройства
FromHdcInternal Статический. Внутренний метод. Не используется
FromHwnd Статический. Создает новый объект Graphics из указанного дескриптора для окна
FromHwndInternal Статический. Внутренний метод. Не используется
FromImage Статический. Создает новый объект Graphics из заданного объекта Image
GetHalftonePalette Статический. Получает дескриптор текущей полутоновой палитры Windows
GetHashCode Служит хэш-функцией для конкретного типа, пригоден для использования в алгоритмах хэширования и структурах данных, например в хэш-таблице
GetHdc Получает дескриптор контекста устройства, связанный с данным объектом Graphics
GetLifetimeService Извлекает служебный объект текущего срока действия, который управляет средствами срока действия данного экземпляра
GetNearestColor Получает цвет, ближайший к указанной структуре Color
GetType Возвращает Type текущего экземпляра
InitializeLifetimeService Получает служебный объект срока действия, для управления средствами срока действия данного экземпляра
IntersectClip Перегружен. Обновляет вырезанную область данного объекта Graphics, включая в нее пересечение текущей вырезанной области и указанной структуры Rectangle
IsVisible Перегружен. Указывает, содержится ли точка, заданная с помощью пары координат, в видимой вырезанной области данного объекта Graphics
MeasureCharacterRanges Получает массив объектов Region, каждый из которых связывает диапазон позиций символов в рамках указанной строки
MeasureString Перегружен. Измеряет указанную строку в процессе ее создания с помощью заданного объекта Font
MultiplyTransform Перегружен. Умножает универсальное преобразование данного объекта Graphics на преобразование указанного объекта Matrix
ReleaseHdc Освобождает дескриптор контекста устройства, полученный в результате предыдущего вызова метода GetHdc данного объекта Graphics
ReleaseHdcInternal Внутренний метод. Не используется
ResetClip Сбрасывает вырезанную область данного объекта Graphics и делает ее бесконечной
ResetTransform Сбрасывает матрицу универсального преобразования данного объекта Graphics и делает ее единичной матрицей
Restore Восстанавливает состояние данного объекта Graphics, возвращая его к состоянию объекта GraphicsState
RotateTransform Перегружен. Применяет заданное вращение к матрице преобразования данного объекта Graphics
Save Сохраняет текущее состояние данного объекта Graphics и связывает сохраненное состояние с объектом GraphicsState
ScaleTransform Перегружен. Применяет указанную операцию масштабирования к матрице преобразования данного объекта Graphics путем ее добавления к матрице преобразования объекта
SetClip Перегружен. Задает в качестве вырезанной области данного объекта Graphics свойство Clip указанного объекта Graphics
ToString Возвращает String, который представляет текущий Object
TransformPoints Перегружен. Преобразует массив точек из одного координатного пространства в другое, используя текущее универсальное преобразование и преобразование страницы данного объекта Graphics
TranslateClip Перегружен. Переводит вырезанную область данного объекта Graphics в указанном объеме в горизонтальном и вертикальном направлениях.
TranslateTransform Перегружен. Добавляет заданный перевод к матрице преобразования данного объекта Graphics
Защищенные методы
Finalize Переопределен. См. Object.Finalize.

В языках C# и C++ для функций финализации используется синтаксис деструктора

MemberwiseClone Создает неполную копию текущего Object

Битовая карта как поверхность для рисования

Приводимое ниже приложение демонстрирует технику рисования на невидимых виртуальных поверхностях – в буквальном смысле в оперативной памяти.

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

Демонстрация предварительно нарисованной в памяти картинки происходит при помощи элемента управления типа PictureBox, который благодаря свойству объекта Image обеспечивает быстрое отображение выводимой графической информации.

Итак, данное Windows-приложение включает объявление трех классов:

  • класса xPoint, объекты которого периодически изменяют собственное положение в пределах клиентской области окна;
  • класса cForm, который обладает свойствами сохранения постоянного соотношения собственных размеров и размеров клиентской области, и обеспечивает отображение множества блуждающих объектов – представителей класса xPoint ;
  • класса Program, который в соответствии с предопределенными алгоритмами обеспечивает создание и выполнение приложения.
  • Класс Program

    Создается автоматически. Без комментариев.

    using System;
     using System.Collections.Generic;
     using System.Windows.Forms;
    
     namespace cForm
     {
         static class Program
         {
             
             // The main entry point for the application.
             
             static void Main()
             {
                 Application.EnableVisualStyles();
                 Application.SetCompatibleTextRenderingDefault(false);
                 Application.Run(new cForm());
             }
         }
     }

    Класс xPoint

    Объявление класса блуждающих объектов:

    using System;
     using System.Collections.Generic;
     using System.Drawing;
     using System.Text;
     namespace cForm
     {
     class xPoint
     {
     // Собственный статический генератор случайных чисел.
     // Используется в конструкторе.
     public static Random rnd = new Random();
    
     // Цвет объекта.
     public Color xColor;
    
     // Текущая позиция. Относительные значения координат X и Y.
     public Point p;
    
     // Обеспечение перемещения. Текущие значения координат могут
     // изменяться как по X, так и по Y.
     public Point direction;
    
     // Счетчик циклов сохранения выбранного направления.
     // Объект на протяжении фиксированного интервала времени может 
     // сохранять ранее избранное направление движения.
     // В течение n.X "тиков" для X в течение n.Y "тиков" для Y.
     public Point n;
    
     public xPoint(int X, int Y, int Xn, int Yn)
     {
     n = new Point(rnd.Next(0, Xn), rnd.Next(0, Yn));
     direction = new Point(rnd.Next(-1, 2), rnd.Next(-1, 2));
     p = new Point(X, Y);
     xColor = 
       Color.FromArgb(150, rnd.Next(0, 256), rnd.Next(0, 256), rnd.Next(0, 256));
     }
    
     // Статический метод. Еще вопрос, где следовало размещать его 
     // объявление... Определение нового положения амебы. 
     // Просматривается ВЕСЬ список.
     // Ее перемещение ограничивается физическими размерами клиентской области
     // окна приложения и определяется по двум координатам (X и Y).
     // В каждый момент она может оставаться на месте, либо изменить
     //  свое положение на один "шаг" по каждой из осей координат
     // ("вверх" или "вниз" по оси Y и "вперед" или "назад" по оси X).
     public static void setNextPosition(cForm cf, xPoint[] pt)
     {
     int i;
     float xy;
    
     // Итак, определение текущей позиции объекта.
     // Просмотр массива...
     for (i = 0; i < pt.Length; i++)
     {
     // Сначала разбираемся со значением координаты X.
     // Вычисляем возможную позицию после перемещения объекта.
     xy = (float)((pt[i].p.X + pt[i].direction.X) * cf.rPointGet);
     // Вполне возможно, что это вполне подходящая позиция.
     // И надо всего лишь проверить две вещи:
     // 1. не выскочит ли объект за пределы клиентской области окна 
     // приложения,
     // 2. не настало ли время поменять направление движения.
     if (
     xy < 0 || xy > cf.ClientSize.Width 	// 1. 
     ||
     pt[i].n.X > cf.NX                	// 2.
     )
     {
     pt[i].n.X = 0; // Обнулили счетчик циклов сохранения выбранного направления.
     // Процедура изменения направления перемещения по оси X.
     // На ближайшую перспективу объект может переместиться
     // вперед:            pt[i].direction.X == 1,
     // назад:             pt[i].direction.X == –1,
     // остаться на месте: pt[i].direction.X == 0.
     // Главное — это не выйти за пределы клиентской области окна приложения.
         pt[i].direction.X = xPoint.rnd.Next(-1, 2);
         xy = (float)((pt[i].p.X + pt[i].direction.X) * cf.rPointGet);
         if (xy >= 0  xy <= cf.ClientSize.Width)
         {
             // Направление выбрано, перемещение произведено.
             pt[i].p.X += pt[i].direction.X;
         }
         else
         {
             // Выбранное направление движения приводит к выходу объекта
             // за пределы клиентской области окна приложения.
             // На ближайшие cf.NX тактов объект остается неподвижен по оси X.  
             pt[i].direction.X = 0;
         }
     }
     else
     {
     // Осуществили очередное перемещение по оси X.
     pt[i].p.X += pt[i].direction.X;
     pt[i].n.X++;
     }
    
     xy = (float)((pt[i].p.Y + pt[i].direction.Y) * cf.rPointGet);
     // Вполне возможно, что это вполне подходящая позиция.
     // И надо всего лишь проверить две вещи:
     // 1. не выскочит ли объект за пределы клиентской области 
     // окна приложения,
     // 2. не настало ли время поменять направление движения.
     if (
     xy < 0 || xy > cf.ClientSize.Height // 1. 
     ||
     pt[i].n.Y > cf.NY                   // 2.
     )
     {
     pt[i].n.Y = 0; // Обнулили счетчик циклов сохранения выбранного направления.
     // Процедура изменения направления перемещения по оси Y.
     // На ближайшую перспективу объект может переместиться
     // вверх:             pt[i].direction.Y == 1,
     // вниз:              pt[i].direction.Y == -1,
     // остаться на месте: pt[i].direction.Y == 0.
     // Главное — это не выйти за пределы клиентской области окна приложения.
     pt[i].direction.Y = xPoint.rnd.Next(-1, 2);
     xy = (float)((pt[i].p.Y + pt[i].direction.Y) * cf.rPointGet);
     if (xy >= 0  xy <= cf.ClientSize.Height)
     {
         // Направление выбрано, перемещение произведено.
         pt[i].p.Y += pt[i].direction.Y;
     }
     else
     {
         // Выбранное направление движения приводит к выходу объекта
         // за пределы клиентской области окна приложения.
         // На ближайшие cf.NY тактов объект остается неподвижен по оси Y.  
         pt[i].direction.Y = 0;
     }
     }
     else
     {
     // Осуществили очередное перемещение по оси Y.
     pt[i].p.Y += pt[i].direction.Y;
     pt[i].n.Y++;
     }
     }
     }
     }
     }

    Класс cForm

    Partial-класс. Содержит объявление класса формы приложения. Первая часть объявления в основном создается автоматически. Следует обратить внимание на настройку событий:

    namespace cForm
     {
     partial class cForm
     {
    
     // Required designer variable.
    
     private System.ComponentModel.IContainer components = null;
    
     // Clean up any resources being used.
     // <param name="disposing">true if managed resources should be disposed;
     // otherwise, false.</param>
     protected override void Dispose(bool disposing)
     {
         if (disposing  (components != null))
         {
             components.Dispose();
         }
         base.Dispose(disposing);
     }
    
     #region Windows Form Designer generated code
    
    
     // Required method for Designer support - do not modify
     // the contents of this method with the code editor.
    
     private void InitializeComponent()
     {
         this.components = new System.ComponentModel.Container();
         this.mainPictureBox = new System.Windows.Forms.PictureBox();
         this.mainTimer = new System.Windows.Forms.Timer(this.components);
       ((System.ComponentModel.ISupportInitialize)(this.mainPictureBox)).
                             BeginInit();
         this.SuspendLayout();
         // 
         // mainPictureBox
         // 
         this.mainPictureBox.BackColor = System.Drawing.Color.White;
         this.mainPictureBox.BorderStyle =
                       System.Windows.Forms.BorderStyle.FixedSingle;
         this.mainPictureBox.Dock = System.Windows.Forms.DockStyle.Fill;
         this.mainPictureBox.Location = new System.Drawing.Point(0, 0);
         this.mainPictureBox.Name = "mainPictureBox";
         this.mainPictureBox.Size = new System.Drawing.Size(569, 538);
         this.mainPictureBox.TabIndex = 0;
         this.mainPictureBox.TabStop = false;
         // 
         // mainTimer
         // 
         this.mainTimer.Interval = 250;
         this.mainTimer.Tick += new System.EventHandler(this.mainTimer_Tick);
         // 
         // cForm
         // 
         this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
         this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
         this.ClientSize = new System.Drawing.Size(569, 538);
         this.Controls.Add(this.mainPictureBox);
         this.Name = "cForm";
         this.Text = "cForm";
     this.Paint +=
                   new System.Windows.Forms.PaintEventHandler(this.bForm00_Paint);
     this.Layout +=
     new System.Windows.Forms.LayoutEventHandler(this.bForm00_Layout);
    ((System.ComponentModel.ISupportInitialize)(this.mainPictureBox)).EndInit();
     this.ResumeLayout(false);
     }
    
     #endregion
    
     private System.Windows.Forms.PictureBox mainPictureBox;
    
     // Определение неизменяемых характеристик рамки окна приложения. 
     private void GetBordersGabarits()
     {
         this.borderHeight = this.Height - this.ClientSize.Height;
         this.borderWidth = this.Width - this.ClientSize.Width;        
     }
    
     // Определение предельных габаритов окна приложения.
     private void SetMinMaxSize()
     {
      this.MinimumSize =
        new System.Drawing.Size(minWidth + borderWidth, minHeight + borderHeight);
      this.MaximumSize =
        new System.Drawing.Size(maxWidth + borderWidth, maxHeight + borderHeight);
     }
     }
     }

    Вторая часть объявления. Здесь сосредоточены методы управления поведением популяции амеб, методы масштабирования внешнего вида приложения и отображения информации.

    using System;
     using System.Collections.Generic;
     using System.ComponentModel;
     using System.Data;
     using System.Drawing;
     using System.Text;
     using System.Windows.Forms;
    
     namespace cForm
     {
     public partial class cForm : Form
     {
     // Средства для отображения объектов на плоскости.
     Color backColor;
     Pen greedPen;
     Pen pen0;
     SolidBrush br;
    
     // Действующие лица. Массив объектов xPoint.
     xPoint[] pt;
    
     // Количество точек.
     const int nPT = 10000;
    
     // Синхронизаторы изменения направления перемещения объектов.
     public int NX, NY;
    
     // Предельные характеристики размеров клиентской области. 
     const int minHeight = 100;
     const int minWidth = 100;
     const int maxHeight = 950;
     const int maxWidth = 950;
    
     // Средство масштабирования. Всеобщая единица измерения.
     private double rPoint;
    
     // Абсолютные неизменяемые характеристики рамки окна приложения.
     int borderHeight;
     int borderWidth;
    
     // Область рисования. Изображение формируется в памяти.
     // На "поверхности" битовой карты
     // (объект - представитель класса Graphics, 
     // создается в результате выполнения метода FromImage),
     // средствами векторной графики (методы класса Graphics) 
     // рисуется картинка.
     // Изображение проецируется на поверхность элемента управления 
     // mainPictureBox 
     // путем модификации свойства Image этого элемента управления.
     private Bitmap bmp;
    
     // Таймер. Фактически представляет собой делегат,
     // который через фиксированные интервалы
     // времени активизирует соответствующее событие
     // (передает управление методу mainTimer_Tick).
     private System.Windows.Forms.Timer mainTimer;
    
     // Конструктор формы.
     public cForm()
     {
     int i;
    
     // Цвет фона картинки. Используется при перерисовке изображения.
     backColor = Color.FromArgb(255,0,0,0);
    
     // Средства для рисования.
     greedPen = new Pen(Color.FromArgb(50, 0, 0, 255), 1);
     pen0 = new Pen(Color.FromArgb(255,0,0,0),1);
     br = new SolidBrush(Color.FromArgb(0, 0, 0, 0));
    
     // Обязательно смотреть код начальной инициализации элементов формы!
     InitializeComponent();
    
     // Определение неизменяемых характеристик окна приложения (формы).
     GetBordersGabarits();
    
     // Начальная коррекция размеров клиентской области окна приложения.
     // "Прямой" вызов метода - обработчика события изменения размеров 
     // окна приложения.
     bForm00_Layout(null, null);
    
     // Определение предельных габаритов окна приложения. 
     SetMinMaxSize();
    
     // Значения синхронизаторов.
     // Неплохо приспособить специальные элементы управления,
     // которые позволяли бы изменять эти значения в интерактивном режиме!
     NX = 50;
     NY = 50;
    
     // Инициализация популяции.
     // Все располагаются в одном месте – в центре клиентской области окна.
     // Одинаковые значения двух последних параметров приводят к тому, что
     // члены популяции синхронно изменяют направление движения. 
     pt = new xPoint[nPT];
     for (i = 0; i < pt.Length; i++)
     {
     pt[i] = new xPoint(
       (int)(this.ClientSize.Width  / (2*rPoint)),
       (int)(this.ClientSize.Height / (2*rPoint)),
        0, //NX, // xPoint.rnd.Next(0, NX+1), // А такие значения нарушают 
        0  //NY  // xPoint.rnd.Next(0, NY+1) // синхронность поведения объектов.
        );
     }
    
     // Процесс пошел!
     mainTimer.Start();
     }
    
     // Определение относительной величины rPoint реализовано как свойство.
     // Замечательная особенность свойства!
     // Оно имеет явную спецификацию возвращаемого значения.
     // И точно такого же типа должен быть единственный параметр value!
     private Size rPointSet
     {            
     set
     { 
     Size s = value;
     rPoint = Math.Sqrt(2.0*s.Width*s.Height) * 0.002;            
     }        
     }
    
     // А вот перегрузить свойство нельзя! Невидимый параметр value 
     // и возвращаемое значение свойства должны быть одного типа. 
     // Именно поэтому МНЕ пришлось вводить пару свойств.
     public double rPointGet
     {
     get
     {
     return rPoint;
     }
     }        
    
     // Обработчик события перерисовки формы.
     // В списке параметров ссылка на объект - инициализатор события,
     // а также ссылка на объект – носитель информации об инкапсуляторе
     // данной поверхности рисования.
     // Способ получения этой информации простой – через свойство Graphics:
     //      Graphics gr = e.Graphics;
     // И знай рисуй себе!
     // Однако эта ссылка нам не понадобится, поскольку мы рисуем
     // не на ПОВЕРХНОСТИ ЭЛЕМЕНТА УПРАВЛЕНИЯ,
     // а в памяти, на ПОВЕРХНОСТИ БИТОВОЙ КАРТЫ. 
     private void bForm00_Paint(object sender, PaintEventArgs e)
     {
     xRedraw(); 
     }
                   
     // Событие Layout возникает при удалении или добавлении дочерних
     // элементов управления,
     // изменении границ элемента управления и других изменениях, 
     // в том числе и изменении размеров формы, которые могут повлиять 
     // на макет элемента.
     // Рекомендуется использовать именно это событие,
     // а не события ..._Resize или ..._SizeChanged. Как сказано 
     // в руководстве, событие Layout возникает в ответ на события
     // ..._Resize и ..._SizeChanged,
     // а также в других ситуациях, когда может понадобиться применение макета.
     private void bForm00_Layout(object sender, LayoutEventArgs e)
     {
     // Использование сразу ДВУХ величин – длины и ширины клиентской 
     // области окна!
     // Вот оптимальное решение проблемы поддержки ПОСТОЯННОГО соотношения
     // характеристик клиентской области  
     // (среднее арифметическое для поддержки равенства сторон).
     // ПЛЮС поправка на размеры рамки окна приложения. 
    
     Size = new System.Drawing.Size
         (
         (ClientSize.Width + ClientSize.Height)/2 + borderWidth,
         (ClientSize.Width + ClientSize.Height)/2 + borderHeight
         );
    
     // После коррекции размеров окна – устанавливаем значение величины 
     // rPoint, которое производится через обращение к свойству rPointSet.   
     rPointSet = this.ClientSize;
    
     // Новая битовая карта под новый размер клиентской области.
     bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
    
     // Объявляется недопустимой конкретная область элемента управления 
     // (здесь форма) и происходит отправка соответствующего сообщения
     // (Paint) элементу управления (форме). При этом значение 
     // параметра (true) 
     // объявляет недопустимыми назначенные элементу управления 
     // дочерние элементы.
     // Для каждого элемента автоматически формируется 
     // объект-представитель
     // класса Graphics, инкапсулирующий поверхность для рисования.
     // Для активизации процесса перерисовки соответствующего 
     // элемента управления требуется объявить метод – обработчик события
     // (в нашем случае это bForm00_Paint).
     this.Invalidate(false); 
     }
    
     // Обработчик события таймера:
     // всем амебам надлежит переопределить собственные координаты и
     // перерисовать картинку! Здесь также можно было бы объявить 
     // недействительной и требующей перерисовки поверхность формы.
     // Это просто: this.Invalidate(false);
     // Однако никто не помешает нам сделать все напрямую, через метод xRedraw.  
     private void mainTimer_Tick(object sender, EventArgs e)
     {
     xPoint.setNextPosition(this, pt);
     xRedraw();
     }
    
     // Перерисовка.
     private void xRedraw()
     {
     // Поверхность для рисования на битовой карте!
     Graphics gr = Graphics.FromImage(bmp);
    
     // Очистить поверхность и закрасить ее в ненавязчивый черный цвет!
     gr.Clear(backColor);
    
     // Нарисовать решетку!
     DrawGreed(gr);
    
     // Нарисовать объекты!
     foreach (xPoint xp in pt)
     {
     // Сообщили кисти цвет объекта... 
     br.Color = xp.xColor;
     // Закрасили объект.
     gr.FillEllipse(br,
                    (float)((xp.p.X * rPoint) - rPoint),
                    (float)((xp.p.Y * rPoint) - rPoint),
                    (float)(2 * rPoint),
                    (float)(2 * rPoint));
     // Сообщили перу цвет объекта... 
     pen0.Color = xp.xColor;
     // Нарисовали контур амебы...
     gr.DrawEllipse(pen0,
                    (float)((xp.p.X * rPoint) - rPoint),
                    (float)((xp.p.Y * rPoint) - rPoint),
                    (float)(2 * rPoint),
                    (float)(2 * rPoint));
     }
    
     // Рисование закончено. Подготовить объект-поверхность к удалению.
     gr.Dispose();
    
     // Отобразить картинку!
     // Это всего лишь модификация свойства Image элемента управления PictureBox. 
     this.mainPictureBox.Image = bmp;
     }
    
     // На поверхности битовой карты (параметр gr) рисуется координатная сетка. 
     private void DrawGreed(Graphics gr)
     {
     float i;
     float w = (float)(this.ClientSize.Width/25.0F);
     float h = (float)(this.ClientSize.Height/25.0F);
     float W = this.ClientSize.Width;
     float H = this.ClientSize.Height;
    
     for (i = h; i < H; i += h)
     {
     gr.DrawLine(this.greedPen, 0, i, W, i);
     }
    
     for (i = w; i < W; i += w)
     {
     gr.DrawLine(this.greedPen, i, 0, i, H);
     }
     }
     }
     }

    Запустили приложение, порадовались отсутствию утомляющего глаза мигания, характерного для непосредственного рисования на поверхности элемента управления... подумали над созданием элементов управления для изменения синхронности перемещения членов амебной популяции.

    GraphicsPath

    GraphicsPath – класс, представляющий последовательность соединенных линий и кривых. Приложения используют контуры для отображения очертаний фигур, заполнения внутренних областей фигур, создания областей отсечения.

    Контур может состоять из любого числа фигур (контуров). Каждая фигура либо составлена из последовательности линий и кривых, либо является геометрическим примитивом. Начальная точка фигуры – первая точка в последовательности соединенных линий и кривых. Конечная точка – последняя точка в последовательности.

    Фигура, состоящая из последовательности соединенных линий и кривых (чьи начальная и конечная точки могут совпадать), является разомкнутой фигурой, если она не замкнута явно. Фигура может быть замкнута явно с помощью метода CloseFigure, который замыкает фигуру путем соединения конечной и начальной точек линией. Фигура, состоящая из геометрического примитива, является замкнутой.

    Для целей заполнения и отсечения (например, если контур визуализируется с помощью метода Graphics.FillPath ) все разомкнутые фигуры замыкаются путем добавления линии от первой точки фигуры к последней.

    Новая фигура начинается неявно, когда создается контур или фигура замыкается. Новая фигура создается явно, когда вызывается метод StartFigure.

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

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

    Конструкторы
    GraphicsPath -конструктор Инициализирует новый экземпляр класса GraphicsPath с перечислением FillMode из Alternate
    Свойства
    FillMode Получает или задает перечисление FillMode, определяющее, как заполняются внутренние области фигур в объекте GraphicsPath
    PathPoints Получает точки в контуре
    PathTypes Получает типы соответствующих точек в массиве PathPoints
    PointCount Получает число элементов в массиве PathPoints или PathTypes
    Методы
    AddArc Присоединяет дугу эллипса к текущей фигуре
    AddBezier Добавляет в текущую фигуру кривую Безье третьего порядка
    AddBeziers Добавляет в текущую фигуру последовательность соединенных кривых Безье третьего порядка
    AddClosedCurve Добавляет замкнутую кривую к данному контуру. Используется кривая фундаментального сплайна, поскольку кривая проходит через все точки массива
    AddCurve Добавляет в текущую фигуру кривую сплайна. Используется кривая фундаментального сплайна, поскольку кривая проходит через все точки массива
    AddEllipse Добавляет эллипс к текущему пути
    AddLine Добавляет отрезок прямой к объекту GraphicsPath
    AddLines Добавляет последовательность соединенных отрезков прямых в конец объекта GraphicsPath
    AddPath Добавляет указанный объект GraphicsPath к данному контуру
    AddPie Добавляет контур сектора к данному контуру
    AddPolygon Добавляет многоугольник к данному контуру
    AddRectangle Добавляет прямоугольник к данному контуру
    AddRectangles Добавляет последовательность прямоугольников к данному контуру
    AddString Добавляет строку текста в данный путь
    ClearMarkers Удаляет все маркеры из данного контура
    Clone Создает точную копию данного контура
    CloseAllFigures Замыкает все незамкнутые фигуры в данном контуре и открывает новую фигуру. Каждая незамкнутая фигура замыкается путем соединения ее начальной и конечной точек линией
    CloseFigure Замыкает текущую фигуру и открывает новую. Если текущая фигура содержит последовательность соединенных линий и кривых, то метод замыкает ее путем соединения начальной и конечной точек линией
    CreateObjRef (унаследовано от Marshal By RefObject ) Создает объект, который содержит всю необходимую информацию для конструирования прокси-сервера, используемого для коммуникации с удаленными объектами
    Dispose Освобождает все ресурсы, используемые объектом GraphicsPath
    Equals (унаследовано от Object ) Определяет, равны ли два экземпляра Object
    Flatten Преобразует каждую кривую в данном контуре в последовательность соединенных отрезков прямых
    GetBounds Возвращает прямоугольник, ограничивающий объект GraphicsPath
    GetHashCode (унаследовано от Object) Служит хэш-функцией для конкретного типа, пригоден для использования в алгоритмах хэширования и структурах данных, например, в хэш-таблице
    GetLastPoint Получает последнюю точку массива PathPoints объекта GraphicsPath
    GetLifetimeService (унаследовано от MarshalByRefObject ) Извлекает служебный объект текущего срока действия, который управляет средствами срока действия данного экземпляра
    GetType (унаследовано от Object ) Возвращает Type текущего экземпляра
    InitializeLifetimeService (унаследовано от MarshalByRefObject ) Получает служебный объект срока действия, для управления средствами срока действия данного экземпляра
    IsOutlineVisible Указывает, содержится ли определенная точка внутри (под) контура объекта GraphicsPath при отображении его с помощью указанного объекта Pen
    IsVisible Определяет, содержится ли указанная точка в объекте GraphicsPath
    Reset Очищает массивы PathPoints и PathTypes и устанавливает FillMode в Alternate
    Reverse Изменяет порядок точек в массиве PathPoints объекта GraphicsPath на противоположный
    SetMarkers Устанавливает маркер на объекте GraphicsPath
    StartFigure Открывает новую фигуру, не замыкая при этом текущую. Все последующие точки, добавляемые к контуру, добавляются к новой фигуре
    ToString (унаследовано от Object ) Возвращает String, который представляет текущий Object
    Transform Применяет матрицу преобразования к объекту GraphicsPath
    Warp Применяет преобразование перекоса, определяемое прямоугольником и параллелограммом, к объекту GraphicsPath
    Widen Заменяет данный контур кривыми, которые окружают область, заполняемую при отображении контура указанным пером
    Защищенные методы
    Finalize Переопределен. См. Object.Finalize.

    В языках C# и C++ для функций финализации используется синтаксис деструктора

    MemberwiseClone (унаследовано от Object ) Создает неполную копию текущего Object

    Region

    Класс Region (Область) предназначается для создания объектов, которые описывают внутреннюю часть графической формы из прямоугольников и фигур, составленных из замкнутых линий. Этот класс не наследуется.

    Область является масштабируемой. Приложение может использовать области для фиксации выходных данных операций рисования. Диспетчер окон применяет области для определения области изображения окон. Эти области называются вырезанными. Приложение может также использовать области в операциях проверки наличия данных, например пересечения точки или прямоугольника с областью. Приложение может заполнять область с помощью объекта Brush.

    Множество пикселей, входящих в состав региона, может состоять из нескольких несмежных участков.

    Список членов класса представляется ниже.

    Открытые конструкторы
    Region -конструктор Инициализирует новый объект Region
    Открытые методы
    Clone Создает точную копию объекта Region
    Complement Обновляет объект Region, чтобы включить часть указанной структуры RectangleF, не пересекающуюся с объектом Region
    CreateObjRef (унаследовано от MarshalByRefObject ) Создает объект, который содержит всю необходимую информацию для создания прокси-сервера, используемого для коммуникации с удаленными объектами
    DisposeEquals Освобождает все ресурсы, используемые объектом Region
    Exclude Обновляет объект Region, чтобы включить часть его внутренней части, не пересекающуюся с указанной структурой Rectangle
    FromHrgn Инициализирует новый объект Region из дескриптора указанной существующей области GDI
    GetBounds Возвращает структуру RectangleF, которая представляет прямоугольник, ограничивающий объект Region на поверхности рисунка объекта Graphics
    GetHashCode (унаследовано от Object ) Служит хэш-функцией для конкретного типа, пригоден для использования в алгоритмах хэширования и структурах данных, например в хэш-таблице
    GetHrgn Возвращает дескриптор Windows для объекта Region в указанном графическом контексте
    GetLifetimeService (унаследовано от MarshalByRefObject ) Извлекает служебный объект текущего срока действия, который управляет средствами срока действия данного экземпляра
    GetRegionData Возвращает объект RegionData, который представляет данные, описывающие объект Region
    GetRegionScans Возвращает массив структур RectangleF, аппроксимирующих объект Region
    GetType (унаследовано от Object ) Возвращает Type текущего экземпляра
    InitializeLifetimeService (унаследовано от MarshalByRefObject ) Получает служебный объект срока действия для управления средствами срока действия данного экземпляра
    Intersect Заменяет объект Region на его пересечение с указанным объектом Region
    IsEmpty Проверяет, имеет ли объект Region пустую внутреннюю часть на указанной поверхности рисунка
    IsInfinite Проверяет, имеет ли объект Region пустую внутреннюю часть на указанной поверхности рисунка
    IsVisible Проверяет, содержится ли указанный прямоугольник в объекте Region
    MakeEmpty Инициализирует объект Region для пустой внутренней части
    MakeInfinite Инициализирует объект Region для бесконечной внутренней части
    ToString (унаследовано от Object ) Возвращает String, который представляет текущий Object
    Transform Преобразует этот объект Region с помощью указанного объекта Matrix
    Translate Смещает координаты объекта Region на указанную величину
    Union Заменяет объект Region на его объединение с указанным объектом GraphicsPath
    Xor Заменяет объект Region на разность объединения и его пересечения с указанным объектом GraphicsPath
    Защищенные методы
    Finalize Переопределен. См. Object.Finalize.

    В языках C# и C++ для функций финализации используется синтаксис деструктора

    MemberwiseClone (унаследовано от Object ) Создает неполную копию текущего Object

    Применение классов GraphicsPath и Region. Круглая форма

    using System;
     using System.Drawing;
     using System.Drawing.Drawing2D;
     using System.Collections;
     using System.ComponentModel;
     using System.Windows.Forms;
    
     namespace StrangeControls
     {
    
     // Объявляется класс – наследник базового класса Form.
     // Наша форма, конечно же, основывается на обычной классической
     // прямоугольной, масштабируемой форме.
     // Прежде всего это означает, что у нее имеется свойство Size,
     // значения которого используются для определения размеров
     // составляющих нашу форму элементов.
     // Наша форма состоит из двух элементов:
     // прямоугольника-заголовка
     // (здесь должны размещаться основные элементы управления формы);
     // эллипсовидной клиентской области с голубой каемочкой.    
    
     public class RoundForm : System.Windows.Forms.Form
     {
     private System.ComponentModel.Container components = null;
     // Объект headSize используется для управления размерами формы.
     private Size headSize;
     // bw – (border width) это переменная,
     // сохраняющая метрические характеристики рамки.
     // В дальнейшем это значение используется для определения 
     // конфигурации нашей формы.
     int bw;
    
     // Ничем не примечательный конструктор...
     public RoundForm()
     {		
     	InitializeComponent();
     }
    
     #region Windows Form Designer generated code
    
     // Required method for Designer support – do not modify
     // the contents of this method with the code editor.
    
     private void InitializeComponent()
     {
     // 
     // RoundForm
     // 
     this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
     this.ClientSize = new System.Drawing.Size(292, 273);
     this.Cursor = System.Windows.Forms.Cursors.Cross;
     this.MinimumSize = new System.Drawing.Size(100, 100);
     this.Name = "RoundForm";
     this.Text = "RoundForm";
     this.Resize += new System.EventHandler(this.RoundForm_Resize);
     }
     #endregion
    
     protected override void Dispose( bool disposing )
     {
      if( disposing )
      {
      if(components != null)
       {
        components.Dispose();
       }
      }
     	base.Dispose( disposing );
     }
    
     // Обработчик события, связанного с изменением формы окна, обеспечивает
     // вызов метода, в котором определяются основные характеристики
     // составляющих формы.
     private void RoundForm_Resize(object sender, System.EventArgs e)
     {
     SetSize();
     }
    
     // Код, определяюший габариты ФОРМЫ – весь здесь...
     // Это определение метрических характеристик ФОРМЫ. 
     protected void SetSize()
     {
      // Всего ничего...
      // На основе соответствующей "классической" формы
      // определяются размеры прямоугольной составляющей (заголовка формы).
      int w = this.Size.Width; 
      bw = (int)((w – this.ClientSize.Width)/2);
      int h = this.Size.Height;
      int bh = h – this.ClientSize.Height – bw;
      headSize = new Size(w,bh);		
     }
    
     // В рамках переопределенной виртуальной функции...
     protected override void OnPaint(PaintEventArgs e)
     {
     // Определяем габариты формы.
     SetSize();
     // Получаем ссылку на графический контекст.
     Graphics gr = this.CreateGraphics(); 
     // Карандаш для отрисовки каемочки.
     Pen pen = new Pen(SystemColors.Desktop,bw);
     // Объект, поддерживающий контуры формы.
     GraphicsPath gp = new GraphicsPath();
     // Контуры формы образуются прямоугольником
     //(его характеристики совпадают с заголовком формы).
     // класс GraphicsPath не имеет метода, который позволял
     // бы непосредственно подсоединять прямоугольные области.
     // Поэтому структура Rectangle предварительно определяется.
     // С эллипсом проще. Он подсоединяется "на лету",
     // без предварительного определения.
     Rectangle rect = new Rectangle(0,0,headSize.Width,headSize.Height);
     gp.AddRectangle(rect);
     gp.AddEllipse(bw,
                   headSize.Height,
                   this.ClientSize.Width,
                   this.ClientSize.Height);
     // Сформировали объект, поддерживающий контуры формы.
     // И на его основе создаем объект, который описывает внутреннюю часть
     // графической формы.
     // В нашем случае она состоит из прямоугольника и эллипса.  
     Region reg = new Region(gp);
     // У любой формы имеется свойство Region.
     // У нашей формы – оно прекрасно. 
     this.Region = reg;
     // Рисуем каемочку...
     gr.DrawEllipse(pen,0,0,this.ClientSize.Width,this.ClientSize.Height);
     // Освобождаем занятые ресурсы.
     gr.Dispose();
     }
     }
     }

    Собственные элементы управления

    В этом разделе обсуждаются некоторые аспекты проблемы построения собственных элементов управления.

    Известно по крайней мере три возможных подхода к разработке новых элементов управления:

  • объединение стандартных элементов управления в группы (составные элементы управления);
  • объявление новых классов, наследующих от существующих элементов управления;
  • написание новых элементов "с нуля".
  • Разработка составных элементов управления предполагает объявление класса, производного от класса UserControl и использование Мастера UserControl, для добавления вложенных элементов управления с последующей настройкой образующих элементов.

    Новый элемент управления может быть построен на основе класса – наследника какого-либо из существующих элементов управления. В этом случае в новом классе удается частично использовать функциональности ранее объявленного класса, возможно, сохраняя при этом внешний вид элемента. Например, можно объявить собственный вариант класса кнопки, который будет наследовать классу Button.

    Написание нового элемента "с нуля" отличается от предыдущего варианта разработки выбором базового класса. В этом случае основываются на классе Control, который не предоставляет потомкам даже элементарного графического интерфейса. Процесс визуализации в этом случае обеспечивается переопределяемым обработчиком события Paint. При этом переопределяется виртуальный метод базового класса OnPaint с единственным аргументом типа PaintEventArgs, который содержит информацию о клиентской области элемента управления. Член этого класса объект типа Graphics – обеспечивает формирование представления элемента управления. Второй член класса – объект типа ClipRectangle – описывает доступную клентскую область элемента управления.

    Следует отметить, что между двумя последними способами определения элементов управления не существует четких границ. В обоих случаях основанием для классификации оказывается объем работы по доопределению и переопределению методов и свойств вновь создаваемого класса элементов управления.

    В рассматриваемом ниже примере определения собственного элемента управления используется объект – представитель класса ImageList. Объекты этого класса предназначаются для сохранения рисунков, которые могут отображаться другими элементами управления. В общем случае этот компонент позволяет написать код для унифицированного каталога рисунков. В нашем варианте он используется для изменения внешнего вида элемента управления. К каждому рисунку можно получить доступ с помощью значения индекса этого рисунка. Отображаемые рисунки имеют один и тот же формат и размер, устанавливаемый в свойстве ImageSize. Таким образом, на основе данного свойства может быть реализован эффект масштабирования элемента управления в смысле изменения его видимых размеров в случае изменения клиентских размеров формы:

    using System;
     using System.Collections;
     using System.ComponentModel;
     using System.Drawing;
     using System.Drawing.Drawing2D;
     using System.Data;
     using System.Windows.Forms;
    
     namespace StrangeControls
     {
    
     // Summary description for RoundButton.
     // Хотя класс RoundButton и объявляется на основе базового
     // класса Button, внешнее представление его
     // объектов-представителей реализуется в переопределяемом
     // методе OnPaint с использованием класса ImageList. 
    
     public class RoundButton : Button
     {
     ImageList imgList;
     // Внешнее представление элемента управления меняется
     // в зависимости от состояния элемента. Это состояние
     // зависит от конкретных событий, происходящих с элементом
     // управления. 
     // Индекс, который используется при изменении внешнего
     // представления элемента управления.
     // Внешний вид элемента управления определяется значением
     // переменной indexB, которая меняет значение в рамках
     // переопределяемых обработчиков событий.
     // Функциональность данного элемента управления задана
     // в классе формы, в виде стандартных (непереопределяемых) обработчиков.  
    
     int indexB; 
    
     public RoundButton():base()
     {
     	indexB = 0;
     	imgList = new ImageList();
     	imgList.Images.Add(Image.FromFile(@"jpg0.jpg"));
     	imgList.Images.Add(Image.FromFile(@"jpg1.jpg"));
     	imgList.Images.Add(Image.FromFile(@"jpg2.jpg"));
     	imgList.Images.Add(Image.FromFile(@"jpg3.jpg"));
     	this.ImageList=imgList;
     	
     }
     // Код, управляющий изменением внешнего вида элемента.
     // Сюда передается управление в результате выполнения метода
     // Refresh(). 
     protected override void OnPaint(PaintEventArgs e)
     {
     GraphicsPath gp = new GraphicsPath();
     gp.AddEllipse(10,10,50,50);
     Region reg = new Region(gp);         
     // Свойству Region присваивается новое значение – новый регион! 
     this.Region = reg;
     e.Graphics.DrawImage(ImageList.Images[indexB],10,10,50,50);
     }
    
     protected override void OnClick(EventArgs e)
     {
     	indexB = 0;
     	this.Refresh();
     	base.OnClick (e);
     }
    
     protected override void OnMouseDown(MouseEventArgs e)
     {
     	indexB = 1;
     	this.Refresh();
     	base.OnMouseDown (e);
     }
    
     protected override void OnGotFocus(EventArgs e)
     {
     	indexB = 0;
     	this.Refresh();
     	base.OnGotFocus (e);
     }
    
     protected override void OnLostFocus(EventArgs e)
     {
     	indexB = 0;
     	this.Refresh();
     	base.OnLostFocus(e);
     }
    
     protected override void OnMouseEnter(EventArgs e)
     {
     	indexB = 2;
     	this.Refresh();
     	base.OnMouseEnter (e);
     }
    
     protected override void OnMouseLeave(EventArgs e)
     {
     	indexB = 3;
     	this.Refresh();
     	base.OnMouseLeave (e);
     }
    
     private void InitializeComponent()
     {
     	// 
     	// RoundButton
     	// 
     }
     }
     }

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

    private void InitializeComponent()
     {
     ::::::::::::::::::::
     // 
     // roundButton1
     // 
     this.roundButton1.Cursor = System.Windows.Forms.Cursors.Cross;
     this.roundButton1.Location = new System.Drawing.Point(136, 8);
     this.roundButton1.Name = "roundButton1";
     this.roundButton1.Size = new System.Drawing.Size(72, 72);
     this.roundButton1.TabIndex = 2;
     this.roundButton1.Text = "roundButton1";
     this.roundButton1.Click += new System.EventHandler(this.roundButton_Click);
     ::::::::::::::::::::
     }
     Сам обработчик события в форме объявлен следующим образом:
    
     private void roundButton_Click(object sender, System.EventArgs e)
     {
      if (imgListindex < imgList.Images.Count–1) imgListindex++;
      else                                       imgListindex = 0;
    
      pictureBox1.Image = imgList.Images[imgListindex];
     }

    Следующий фрагмент кода посвящен разработке составного элемента управления, который представляет собой "батарею" из 16 одинаковых кнопочек, располагаемых на одной панели. Несмотря на внушительное количество составляющих элементов, перед нами один элемент управления с общим единым обработчиком события, связанным с нажатием на одну из 16 кнопочек. Естественно, что реализация единого обработчика требует дополнительных усилий: каждой кнопке назначается один и тот же стандартный обработчик с двумя параметрами. Один из параметров используется для идентификации нажатой кнопки. При нажатии на кнопку происходит изменение состояния этой кнопки, которое кодируется посредством текстового значения (свойства Text ), отображаемого на поверхности кнопки.

    using System;
     using System.Collections;
     using System.ComponentModel;
     using System.Drawing;
     using System.Data;
     using System.Windows.Forms;
    
     namespace By2
     {
    
     // Summary description for ButtonsControl.
    
     public class ButtonsControl : System.Windows.Forms.UserControl
     {
      
     // Required designer variable.
     private Form1 f1;
     private ArrayList bArrList;
     private System.Windows.Forms.Panel panel1;
     private System.Windows.Forms.Button button16;
     private System.Windows.Forms.Button button15;
     private System.Windows.Forms.Button button14;
     private System.Windows.Forms.Button button13;
     private System.Windows.Forms.Button button12;
     private System.Windows.Forms.Button button11;
     private System.Windows.Forms.Button button10;
     private System.Windows.Forms.Button button9;
     private System.Windows.Forms.Button button8;
     private System.Windows.Forms.Button button7;
     private System.Windows.Forms.Button button6;
     private System.Windows.Forms.Button button5;
     private System.Windows.Forms.Button button4;
     private System.Windows.Forms.Button button3;
     private System.Windows.Forms.Button button2;
     private System.Windows.Forms.Button button1;
     public ArrayList parameterList; 
    
     public void SetParent(Form1 fKey)
     {
     f1 = fKey;
     }
    
     private System.ComponentModel.Container components = null;
    
     public ButtonsControl()
     {
     InitializeComponent();
     bArrList = new ArrayList();
     bArrList.Add(button16);
     bArrList.Add(button15);
     bArrList.Add(button14);
     bArrList.Add(button13);
     bArrList.Add(button12);
     bArrList.Add(button11);
     bArrList.Add(button10);
     bArrList.Add(button9);
     bArrList.Add(button8);
     bArrList.Add(button7);
     bArrList.Add(button6);
     bArrList.Add(button5);
     bArrList.Add(button4);
     bArrList.Add(button3);
     bArrList.Add(button2);
     bArrList.Add(button1);
     parameterList = new ArrayList();
     }
    
     private void SetParameterList()
     {
     int i, I = bArrList.Count ;
     parameterList.Clear();
     for (i = 0; i < I;  i++)
     {
     parameterList.Add(int.Parse(((Button)bArrList[i]).Text));		 
     }
     f1.formDecimalValue(parameterList);         
     }
    
     public void SetButtons(ArrayList lst)
     {
     int i, I = lst.Count, J = bArrList.Count;
    
     for (i = 0; i < J; i++)
     {
     ((Button)bArrList[i]).Text = "0";		 
     }
    
     for (i = 0; i < I; i++)
     {
     ((Button)bArrList[i]).Text = ((int)lst[i]).ToString();		 
     }
    
     }
    
      
     // Clean up any resources being used.
    
     protected override void Dispose( bool disposing )
     {
     if( disposing )
     {
     	if(components != null)
     	{
     		components.Dispose();
     	}
     }
     base.Dispose( disposing );
     }
    
     #region Component Designer generated code
      
     // Required method for Designer support – do not modify 
     // the contents of this method with the code editor.
    
     private void InitializeComponent()
     {
     this.panel1 = new System.Windows.Forms.Panel();
     this.button16 = new System.Windows.Forms.Button();
     this.button15 = new System.Windows.Forms.Button();
     this.button14 = new System.Windows.Forms.Button();
     this.button13 = new System.Windows.Forms.Button();
     this.button12 = new System.Windows.Forms.Button();
     this.button11 = new System.Windows.Forms.Button();
     this.button10 = new System.Windows.Forms.Button();
     this.button9 = new System.Windows.Forms.Button();
     this.button8 = new System.Windows.Forms.Button();
     this.button7 = new System.Windows.Forms.Button();
     this.button6 = new System.Windows.Forms.Button();
     this.button5 = new System.Windows.Forms.Button();
     this.button4 = new System.Windows.Forms.Button();
     this.button3 = new System.Windows.Forms.Button();
     this.button2 = new System.Windows.Forms.Button();
     this.button1 = new System.Windows.Forms.Button();
     this.panel1.SuspendLayout();
     this.SuspendLayout();
     // 
     // panel1
     // 
     this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
     this.panel1.Controls.Add(this.button16);
     this.panel1.Controls.Add(this.button15);
     this.panel1.Controls.Add(this.button14);
     this.panel1.Controls.Add(this.button13);
     this.panel1.Controls.Add(this.button12);
     this.panel1.Controls.Add(this.button11);
     this.panel1.Controls.Add(this.button10);
     this.panel1.Controls.Add(this.button9);
     this.panel1.Controls.Add(this.button8);
     this.panel1.Controls.Add(this.button7);
     this.panel1.Controls.Add(this.button6);
     this.panel1.Controls.Add(this.button5);
     this.panel1.Controls.Add(this.button4);
     this.panel1.Controls.Add(this.button3);
     this.panel1.Controls.Add(this.button2);
     this.panel1.Controls.Add(this.button1);
     this.panel1.Location = new System.Drawing.Point(8, 8);
     this.panel1.Name = "panel1";
     this.panel1.Size = new System.Drawing.Size(648, 48);
     this.panel1.TabIndex = 0;
     // 
     // button16
     // 
     this.button16.Location = new System.Drawing.Point(605, 12);
     this.button16.Name = "button16";
     this.button16.Size = new System.Drawing.Size(32, 23);
     this.button16.TabIndex = 146;
     this.button16.Text = "0";
     this.button16.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button15
     // 
     this.button15.Location = new System.Drawing.Point(565, 12);
     this.button15.Name = "button15";
     this.button15.Size = new System.Drawing.Size(32, 23);
     this.button15.TabIndex = 145;
     this.button15.Text = "0";
     this.button15.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button14
     // 
     this.button14.Location = new System.Drawing.Point(525, 12);
     this.button14.Name = "button14";
     this.button14.Size = new System.Drawing.Size(32, 23);
     this.button14.TabIndex = 144;
     this.button14.Text = "0";
     this.button14.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button13
     // 
     this.button13.Location = new System.Drawing.Point(485, 12);
     this.button13.Name = "button13";
     this.button13.Size = new System.Drawing.Size(32, 23);
     this.button13.TabIndex = 143;
     this.button13.Text = "0";
     this.button13.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button12
     // 
     this.button12.Location = new System.Drawing.Point(445, 12);
     this.button12.Name = "button12";
     this.button12.Size = new System.Drawing.Size(32, 23);
     this.button12.TabIndex = 142;
     this.button12.Text = "0";
     this.button12.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button11
     // 
     this.button11.Location = new System.Drawing.Point(405, 12);
     this.button11.Name = "button11";
     this.button11.Size = new System.Drawing.Size(32, 23);
     this.button11.TabIndex = 141;
     this.button11.Text = "0";
     this.button11.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button10
     // 
     this.button10.Location = new System.Drawing.Point(365, 12);
     this.button10.Name = "button10";
     this.button10.Size = new System.Drawing.Size(32, 23);
     this.button10.TabIndex = 140;
     this.button10.Text = "0";
     this.button10.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button9
     // 
     this.button9.Location = new System.Drawing.Point(325, 12);
     this.button9.Name = "button9";
     this.button9.Size = new System.Drawing.Size(32, 23);
     this.button9.TabIndex = 139;
     this.button9.Text = "0";
     this.button9.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button8
     // 
     this.button8.Location = new System.Drawing.Point(285, 12);
     this.button8.Name = "button8";
     this.button8.Size = new System.Drawing.Size(32, 23);
     this.button8.TabIndex = 138;
     this.button8.Text = "0";
     this.button8.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button7
     // 
     this.button7.Location = new System.Drawing.Point(245, 12);
     this.button7.Name = "button7";
     this.button7.Size = new System.Drawing.Size(32, 23);
     this.button7.TabIndex = 137;
     this.button7.Text = "0";
     this.button7.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button6
     // 
     this.button6.Location = new System.Drawing.Point(205, 12);
     this.button6.Name = "button6";
     this.button6.Size = new System.Drawing.Size(32, 23);
     this.button6.TabIndex = 136;
     this.button6.Text = "0";
     this.button6.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button5
     // 
     this.button5.Location = new System.Drawing.Point(165, 12);
     this.button5.Name = "button5";
     this.button5.Size = new System.Drawing.Size(32, 23);
     this.button5.TabIndex = 135;
     this.button5.Text = "0";
     this.button5.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button4
     // 
     this.button4.Location = new System.Drawing.Point(125, 12);
     this.button4.Name = "button4";
     this.button4.Size = new System.Drawing.Size(32, 23);
     this.button4.TabIndex = 134;
     this.button4.Text = "0";
     this.button4.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button3
     // 
     this.button3.Location = new System.Drawing.Point(85, 12);
     this.button3.Name = "button3";
     this.button3.Size = new System.Drawing.Size(32, 23);
     this.button3.TabIndex = 133;
     this.button3.Text = "0";
     this.button3.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button2
     // 
     this.button2.Location = new System.Drawing.Point(45, 12);
     this.button2.Name = "button2";
     this.button2.Size = new System.Drawing.Size(32, 23);
     this.button2.TabIndex = 132;
     this.button2.Text = "0";
     this.button2.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button1
     // 
     this.button1.Location = new System.Drawing.Point(5, 12);
     this.button1.Name = "button1";
     this.button1.Size = new System.Drawing.Size(32, 23);
     this.button1.TabIndex = 131;
     this.button1.Text = "0";
     this.button1.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // ButtonsControl
     // 
     this.Controls.Add(this.panel1);
     this.Name = "ButtonsControl";
     this.Size = new System.Drawing.Size(664, 64);
     this.panel1.ResumeLayout(false);
     this.ResumeLayout(false);
    
     }
     #endregion
    
     private void buttonX_Click(object sender, System.EventArgs e)
     {
     if (((Button)sender).Text.Equals("0")) ((Button)sender).Text = "1";
     else                               ((Button)sender).Text = "0";
    
     SetParameterList();
     }
     }
     }
    Страницы:

    GDI+ - это набор программных средств, которые используются в .NET.

    GDI+ позволяют создателям приложений выводить данные на экран или на принтер без необходимости обеспечивать работу с определенными типами устройств отображения. Для отображения информации программисту достаточно вызывать нужные методы классов GDI+. При этом автоматически учитываются типы определенных устройств и выполняются вызовы соответствующих драйверов.

    Graphics

    Класс, который ИНКАПСУЛИРУЕТ поверхность рисования GDI+. Для этого класса не определен ни один конструктор. Видимо, успех в деле ручного конструирования инкапсулятора поверхностей рисования (еще вопрос, сколько разновидностей таких поверхностей) представляется проблематичным.

    Конкретный объект – представитель класса Graphics предоставляется в виде ссылки методами-обработчиками событий либо создается в ходе выполнения ряда методов применительно к конкретным объектам, обладающим "поверхностями рисования" (клиентская область формы, кнопки, панели, битовая матрица):

    Bitmap bmp;
    Pen greedPen;
    :::::
    greedPen = new Pen(Color.FromArgb(50, 0, 0, 255), 1);
    // Новая битовая карта под новый размер клиентской области формы.
    bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
    Graphics gr = Graphics.FromImage(bmp);
    gr.DrawLine(this.greedPen, 0, 0, 100, 100);
    gr.Dispose();

    Ниже представлен список членов класса.

    Clip Получает или задает объект Region, ограничивающий область рисования данного объекта Graphics
    ClipBounds Получает структуру RectangleF, которая заключает в себе вырезанную область данного объекта Graphics
    CompositingMode Получает значение, задающее порядок рисования сложных изображений в данном объекте Graphics
    CompositingQuality Получает или задает качество отображения сложных изображений, которые выводятся в данном объекте Graphics
    DpiX Получает горизонтальное разрешение данного объекта Graphics
    DpiY Получает вертикальное разрешение данного объекта Graphics
    InterpolationMode Получает или задает режим вставки, связанный с данным объектом Graphics
    IsClipEmpty Получает значение, которое указывает, является ли вырезанная область данного объекта Graphics пустой
    IsVisibleClipEmpty Получает значение, которое указывает, является ли видимая вырезанная область данного объекта Graphics пустой
    PageScale Получает или задает масштабирование между универсальными единицами и единицами страницы для данного объекта Graphics
    PageUnit Получает или задает единицу измерения для координат страницы данного объекта Graphics
    PixelOffsetMode Получает или задает значение, которое задает порядок смещения точек во время отображения данного объекта Graphics
    RenderingOrigin Получает или задает исходное заполнение данного объекта Graphics для сглаживания цветовых переходов и для штриховки
    SmoothingMode Получает или задает качество заполнения для данного объекта Graphics
    TextContrast Получает или задает значение коррекции яркости для отображения текста
    TextRenderingHint Получает или задает режим заполнения для текста, связанного с данным объектом Graphics
    Transform Получает или задает универсальное преобразование для данного объекта Graphics
    VisibleClipBounds Получает или задает рабочий прямоугольник видимой вырезанной области данного объекта Graphics
    Открытые методы
    AddMetafileComment Добавляет комментарий к текущему объекту Metafile
    BeginContainer Перегружен. Сохраняет графический контейнер, содержащий текущее состояние данного объекта Graphics, а затем открывает и использует новый графический контейнер
    Clear Очищает всю поверхность рисования и выполняет заливку поверхности указанным цветом фона
    CreateObjRef Создает объект, который содержит всю необходимую информацию для создания прокси-сервера, используемого для коммуникации с удаленными объектами
    Dispose Освобождает все ресурсы, используемые данным объектом Graphics
    DrawArc Перегружен. Рисует дугу, которая является частью эллипса, заданного парой координат, шириной и высотой
    DrawBezier Перегружен. Строит кривую Безье, определяемую четырьмя структурами Point
    DrawBeziers Перегружен. Формирует набор кривых Безье из массива структур Point
    DrawClosedCurve Перегружен. Строит замкнутую фундаментальную кривую, определяемую массивом структур Point
    DrawCurve Перегружен. Строит замкнутую фундаментальную кривую через точки указанного массива структур Point
    DrawEllipse Перегружен. Формирует эллипс, который определяется ограничивающим прямоугольником, заданным с помощью пары координат — ширины и высоты
    DrawIcon Перегружен. Формирует изображение, которое представлено указанным объектом Icon, расположенным по указанным координатам
    DrawIconUnstretched Формирует изображение, представленное указанным объектом Icon, не масштабируя его
    DrawImage Перегружен. Рисует заданный объект Image в заданном месте, используя исходный размер
    DrawImageUnscaled Перегружен. Рисует заданное изображение, используя его исходный фактический размер, в расположении, заданном парой координат
    DrawLine Перегружен. Проводит линию, соединяющую две точки, определенные парами координат
    DrawLines Перегружен. Формирует набор сегментов линии, которые соединяют массив структур Point
    DrawPath Рисует объект GraphicsPath
    DrawPie Перегружен. Рисует сектор, определенный эллипсом, который задан парой координат, шириной, высотой и двумя радиальными линиями
    DrawPolygon Перегружен. Рисует многоугольник, определяемый массивом структур Point
    DrawRectangle Перегружен. Рисует прямоугольник, который определен парой координат, шириной и высотой
    DrawRectangles Перегружен. Рисует набор прямоугольников, определяемых структурой Rectangle
    DrawString Перегружен. Создает текстовую строку в заданном месте с указанными объектами Brush и Font
    EndContainer Закрывает текущий графический контейнер и восстанавливает состояние данного объекта Graphics, которое было сохранено при вызове метода BeginContainer
    EnumerateMetafile Перегружен. Отправляет записи указанного объекта Metafile по отдельности методу обратного вызова, который отображает их в заданной точке
    Equals Перегружен. Определяет, равны ли два экземпляра Object
    ExcludeClip Перегружен. Обновляет вырезанную область данного объекта Graphics, чтобы исключить из нее часть, определенную структурой Rectangle
    FillClosedCurve Перегружен. Заполняет замкнутую фундаментальную кривую, определяемую массивом структур Point
    FillEllipse Перегружен. Заполняет внутреннюю часть эллипса, который определяется ограничивающим прямоугольником, заданным с помощью пары координат — ширины и высоты
    FillPath Заполняет внутреннюю часть объекта GraphicsPath
    FillPie Перегружен. Заполняет внутреннюю часть сектора, определенного эллипсом, который задан парой координат, шириной, высотой и двумя радиальными линиями
    FillPolygon Перегружен. Заполняет внутреннюю часть многоугольника, определенного массивом точек, заданных структурами Point
    FillRectangle Перегружен. Заполняет внутреннюю часть прямоугольника, который определен парой координат, шириной и высотой
    FillRectangles Перегружен. Заполняет внутреннюю часть набора прямоугольников, определяемого структурами Rectangle
    FillRegion Заполняет внутреннюю часть объекта Region
    Flush Перегружен. Вызывает принудительное выполнение всех отложенных графических операций и немедленно возвращается, не дожидаясь их окончания
    FromHdc Статический. Перегружен. Создает новый объект Graphics из указанного дескриптора для контекста устройства
    FromHdcInternal Статический. Внутренний метод. Не используется
    FromHwnd Статический. Создает новый объект Graphics из указанного дескриптора для окна
    FromHwndInternal Статический. Внутренний метод. Не используется
    FromImage Статический. Создает новый объект Graphics из заданного объекта Image
    GetHalftonePalette Статический. Получает дескриптор текущей полутоновой палитры Windows
    GetHashCode Служит хэш-функцией для конкретного типа, пригоден для использования в алгоритмах хэширования и структурах данных, например в хэш-таблице
    GetHdc Получает дескриптор контекста устройства, связанный с данным объектом Graphics
    GetLifetimeService Извлекает служебный объект текущего срока действия, который управляет средствами срока действия данного экземпляра
    GetNearestColor Получает цвет, ближайший к указанной структуре Color
    GetType Возвращает Type текущего экземпляра
    InitializeLifetimeService Получает служебный объект срока действия, для управления средствами срока действия данного экземпляра
    IntersectClip Перегружен. Обновляет вырезанную область данного объекта Graphics, включая в нее пересечение текущей вырезанной области и указанной структуры Rectangle
    IsVisible Перегружен. Указывает, содержится ли точка, заданная с помощью пары координат, в видимой вырезанной области данного объекта Graphics
    MeasureCharacterRanges Получает массив объектов Region, каждый из которых связывает диапазон позиций символов в рамках указанной строки
    MeasureString Перегружен. Измеряет указанную строку в процессе ее создания с помощью заданного объекта Font
    MultiplyTransform Перегружен. Умножает универсальное преобразование данного объекта Graphics на преобразование указанного объекта Matrix
    ReleaseHdc Освобождает дескриптор контекста устройства, полученный в результате предыдущего вызова метода GetHdc данного объекта Graphics
    ReleaseHdcInternal Внутренний метод. Не используется
    ResetClip Сбрасывает вырезанную область данного объекта Graphics и делает ее бесконечной
    ResetTransform Сбрасывает матрицу универсального преобразования данного объекта Graphics и делает ее единичной матрицей
    Restore Восстанавливает состояние данного объекта Graphics, возвращая его к состоянию объекта GraphicsState
    RotateTransform Перегружен. Применяет заданное вращение к матрице преобразования данного объекта Graphics
    Save Сохраняет текущее состояние данного объекта Graphics и связывает сохраненное состояние с объектом GraphicsState
    ScaleTransform Перегружен. Применяет указанную операцию масштабирования к матрице преобразования данного объекта Graphics путем ее добавления к матрице преобразования объекта
    SetClip Перегружен. Задает в качестве вырезанной области данного объекта Graphics свойство Clip указанного объекта Graphics
    ToString Возвращает String, который представляет текущий Object
    TransformPoints Перегружен. Преобразует массив точек из одного координатного пространства в другое, используя текущее универсальное преобразование и преобразование страницы данного объекта Graphics
    TranslateClip Перегружен. Переводит вырезанную область данного объекта Graphics в указанном объеме в горизонтальном и вертикальном направлениях.
    TranslateTransform Перегружен. Добавляет заданный перевод к матрице преобразования данного объекта Graphics
    Защищенные методы
    Finalize Переопределен. См. Object.Finalize.

    В языках C# и C++ для функций финализации используется синтаксис деструктора

    MemberwiseClone Создает неполную копию текущего Object

    Битовая карта как поверхность для рисования

    Приводимое ниже приложение демонстрирует технику рисования на невидимых виртуальных поверхностях – в буквальном смысле в оперативной памяти.

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

    Демонстрация предварительно нарисованной в памяти картинки происходит при помощи элемента управления типа PictureBox, который благодаря свойству объекта Image обеспечивает быстрое отображение выводимой графической информации.

    Итак, данное Windows-приложение включает объявление трех классов:

  • класса xPoint, объекты которого периодически изменяют собственное положение в пределах клиентской области окна;
  • класса cForm, который обладает свойствами сохранения постоянного соотношения собственных размеров и размеров клиентской области, и обеспечивает отображение множества блуждающих объектов – представителей класса xPoint ;
  • класса Program, который в соответствии с предопределенными алгоритмами обеспечивает создание и выполнение приложения.
  • Класс Program

    Создается автоматически. Без комментариев.

    using System;
     using System.Collections.Generic;
     using System.Windows.Forms;
    
     namespace cForm
     {
         static class Program
         {
             
             // The main entry point for the application.
             
             static void Main()
             {
                 Application.EnableVisualStyles();
                 Application.SetCompatibleTextRenderingDefault(false);
                 Application.Run(new cForm());
             }
         }
     }

    Класс xPoint

    Объявление класса блуждающих объектов:

    using System;
     using System.Collections.Generic;
     using System.Drawing;
     using System.Text;
     namespace cForm
     {
     class xPoint
     {
     // Собственный статический генератор случайных чисел.
     // Используется в конструкторе.
     public static Random rnd = new Random();
    
     // Цвет объекта.
     public Color xColor;
    
     // Текущая позиция. Относительные значения координат X и Y.
     public Point p;
    
     // Обеспечение перемещения. Текущие значения координат могут
     // изменяться как по X, так и по Y.
     public Point direction;
    
     // Счетчик циклов сохранения выбранного направления.
     // Объект на протяжении фиксированного интервала времени может 
     // сохранять ранее избранное направление движения.
     // В течение n.X "тиков" для X в течение n.Y "тиков" для Y.
     public Point n;
    
     public xPoint(int X, int Y, int Xn, int Yn)
     {
     n = new Point(rnd.Next(0, Xn), rnd.Next(0, Yn));
     direction = new Point(rnd.Next(-1, 2), rnd.Next(-1, 2));
     p = new Point(X, Y);
     xColor = 
       Color.FromArgb(150, rnd.Next(0, 256), rnd.Next(0, 256), rnd.Next(0, 256));
     }
    
     // Статический метод. Еще вопрос, где следовало размещать его 
     // объявление... Определение нового положения амебы. 
     // Просматривается ВЕСЬ список.
     // Ее перемещение ограничивается физическими размерами клиентской области
     // окна приложения и определяется по двум координатам (X и Y).
     // В каждый момент она может оставаться на месте, либо изменить
     //  свое положение на один "шаг" по каждой из осей координат
     // ("вверх" или "вниз" по оси Y и "вперед" или "назад" по оси X).
     public static void setNextPosition(cForm cf, xPoint[] pt)
     {
     int i;
     float xy;
    
     // Итак, определение текущей позиции объекта.
     // Просмотр массива...
     for (i = 0; i < pt.Length; i++)
     {
     // Сначала разбираемся со значением координаты X.
     // Вычисляем возможную позицию после перемещения объекта.
     xy = (float)((pt[i].p.X + pt[i].direction.X) * cf.rPointGet);
     // Вполне возможно, что это вполне подходящая позиция.
     // И надо всего лишь проверить две вещи:
     // 1. не выскочит ли объект за пределы клиентской области окна 
     // приложения,
     // 2. не настало ли время поменять направление движения.
     if (
     xy < 0 || xy > cf.ClientSize.Width 	// 1. 
     ||
     pt[i].n.X > cf.NX                	// 2.
     )
     {
     pt[i].n.X = 0; // Обнулили счетчик циклов сохранения выбранного направления.
     // Процедура изменения направления перемещения по оси X.
     // На ближайшую перспективу объект может переместиться
     // вперед:            pt[i].direction.X == 1,
     // назад:             pt[i].direction.X == –1,
     // остаться на месте: pt[i].direction.X == 0.
     // Главное — это не выйти за пределы клиентской области окна приложения.
         pt[i].direction.X = xPoint.rnd.Next(-1, 2);
         xy = (float)((pt[i].p.X + pt[i].direction.X) * cf.rPointGet);
         if (xy >= 0  xy <= cf.ClientSize.Width)
         {
             // Направление выбрано, перемещение произведено.
             pt[i].p.X += pt[i].direction.X;
         }
         else
         {
             // Выбранное направление движения приводит к выходу объекта
             // за пределы клиентской области окна приложения.
             // На ближайшие cf.NX тактов объект остается неподвижен по оси X.  
             pt[i].direction.X = 0;
         }
     }
     else
     {
     // Осуществили очередное перемещение по оси X.
     pt[i].p.X += pt[i].direction.X;
     pt[i].n.X++;
     }
    
     xy = (float)((pt[i].p.Y + pt[i].direction.Y) * cf.rPointGet);
     // Вполне возможно, что это вполне подходящая позиция.
     // И надо всего лишь проверить две вещи:
     // 1. не выскочит ли объект за пределы клиентской области 
     // окна приложения,
     // 2. не настало ли время поменять направление движения.
     if (
     xy < 0 || xy > cf.ClientSize.Height // 1. 
     ||
     pt[i].n.Y > cf.NY                   // 2.
     )
     {
     pt[i].n.Y = 0; // Обнулили счетчик циклов сохранения выбранного направления.
     // Процедура изменения направления перемещения по оси Y.
     // На ближайшую перспективу объект может переместиться
     // вверх:             pt[i].direction.Y == 1,
     // вниз:              pt[i].direction.Y == -1,
     // остаться на месте: pt[i].direction.Y == 0.
     // Главное — это не выйти за пределы клиентской области окна приложения.
     pt[i].direction.Y = xPoint.rnd.Next(-1, 2);
     xy = (float)((pt[i].p.Y + pt[i].direction.Y) * cf.rPointGet);
     if (xy >= 0  xy <= cf.ClientSize.Height)
     {
         // Направление выбрано, перемещение произведено.
         pt[i].p.Y += pt[i].direction.Y;
     }
     else
     {
         // Выбранное направление движения приводит к выходу объекта
         // за пределы клиентской области окна приложения.
         // На ближайшие cf.NY тактов объект остается неподвижен по оси Y.  
         pt[i].direction.Y = 0;
     }
     }
     else
     {
     // Осуществили очередное перемещение по оси Y.
     pt[i].p.Y += pt[i].direction.Y;
     pt[i].n.Y++;
     }
     }
     }
     }
     }

    Класс cForm

    Partial-класс. Содержит объявление класса формы приложения. Первая часть объявления в основном создается автоматически. Следует обратить внимание на настройку событий:

    namespace cForm
     {
     partial class cForm
     {
    
     // Required designer variable.
    
     private System.ComponentModel.IContainer components = null;
    
     // Clean up any resources being used.
     // <param name="disposing">true if managed resources should be disposed;
     // otherwise, false.</param>
     protected override void Dispose(bool disposing)
     {
         if (disposing  (components != null))
         {
             components.Dispose();
         }
         base.Dispose(disposing);
     }
    
     #region Windows Form Designer generated code
    
    
     // Required method for Designer support - do not modify
     // the contents of this method with the code editor.
    
     private void InitializeComponent()
     {
         this.components = new System.ComponentModel.Container();
         this.mainPictureBox = new System.Windows.Forms.PictureBox();
         this.mainTimer = new System.Windows.Forms.Timer(this.components);
       ((System.ComponentModel.ISupportInitialize)(this.mainPictureBox)).
                             BeginInit();
         this.SuspendLayout();
         // 
         // mainPictureBox
         // 
         this.mainPictureBox.BackColor = System.Drawing.Color.White;
         this.mainPictureBox.BorderStyle =
                       System.Windows.Forms.BorderStyle.FixedSingle;
         this.mainPictureBox.Dock = System.Windows.Forms.DockStyle.Fill;
         this.mainPictureBox.Location = new System.Drawing.Point(0, 0);
         this.mainPictureBox.Name = "mainPictureBox";
         this.mainPictureBox.Size = new System.Drawing.Size(569, 538);
         this.mainPictureBox.TabIndex = 0;
         this.mainPictureBox.TabStop = false;
         // 
         // mainTimer
         // 
         this.mainTimer.Interval = 250;
         this.mainTimer.Tick += new System.EventHandler(this.mainTimer_Tick);
         // 
         // cForm
         // 
         this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
         this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
         this.ClientSize = new System.Drawing.Size(569, 538);
         this.Controls.Add(this.mainPictureBox);
         this.Name = "cForm";
         this.Text = "cForm";
     this.Paint +=
                   new System.Windows.Forms.PaintEventHandler(this.bForm00_Paint);
     this.Layout +=
     new System.Windows.Forms.LayoutEventHandler(this.bForm00_Layout);
    ((System.ComponentModel.ISupportInitialize)(this.mainPictureBox)).EndInit();
     this.ResumeLayout(false);
     }
    
     #endregion
    
     private System.Windows.Forms.PictureBox mainPictureBox;
    
     // Определение неизменяемых характеристик рамки окна приложения. 
     private void GetBordersGabarits()
     {
         this.borderHeight = this.Height - this.ClientSize.Height;
         this.borderWidth = this.Width - this.ClientSize.Width;        
     }
    
     // Определение предельных габаритов окна приложения.
     private void SetMinMaxSize()
     {
      this.MinimumSize =
        new System.Drawing.Size(minWidth + borderWidth, minHeight + borderHeight);
      this.MaximumSize =
        new System.Drawing.Size(maxWidth + borderWidth, maxHeight + borderHeight);
     }
     }
     }

    Вторая часть объявления. Здесь сосредоточены методы управления поведением популяции амеб, методы масштабирования внешнего вида приложения и отображения информации.

    using System;
     using System.Collections.Generic;
     using System.ComponentModel;
     using System.Data;
     using System.Drawing;
     using System.Text;
     using System.Windows.Forms;
    
     namespace cForm
     {
     public partial class cForm : Form
     {
     // Средства для отображения объектов на плоскости.
     Color backColor;
     Pen greedPen;
     Pen pen0;
     SolidBrush br;
    
     // Действующие лица. Массив объектов xPoint.
     xPoint[] pt;
    
     // Количество точек.
     const int nPT = 10000;
    
     // Синхронизаторы изменения направления перемещения объектов.
     public int NX, NY;
    
     // Предельные характеристики размеров клиентской области. 
     const int minHeight = 100;
     const int minWidth = 100;
     const int maxHeight = 950;
     const int maxWidth = 950;
    
     // Средство масштабирования. Всеобщая единица измерения.
     private double rPoint;
    
     // Абсолютные неизменяемые характеристики рамки окна приложения.
     int borderHeight;
     int borderWidth;
    
     // Область рисования. Изображение формируется в памяти.
     // На "поверхности" битовой карты
     // (объект - представитель класса Graphics, 
     // создается в результате выполнения метода FromImage),
     // средствами векторной графики (методы класса Graphics) 
     // рисуется картинка.
     // Изображение проецируется на поверхность элемента управления 
     // mainPictureBox 
     // путем модификации свойства Image этого элемента управления.
     private Bitmap bmp;
    
     // Таймер. Фактически представляет собой делегат,
     // который через фиксированные интервалы
     // времени активизирует соответствующее событие
     // (передает управление методу mainTimer_Tick).
     private System.Windows.Forms.Timer mainTimer;
    
     // Конструктор формы.
     public cForm()
     {
     int i;
    
     // Цвет фона картинки. Используется при перерисовке изображения.
     backColor = Color.FromArgb(255,0,0,0);
    
     // Средства для рисования.
     greedPen = new Pen(Color.FromArgb(50, 0, 0, 255), 1);
     pen0 = new Pen(Color.FromArgb(255,0,0,0),1);
     br = new SolidBrush(Color.FromArgb(0, 0, 0, 0));
    
     // Обязательно смотреть код начальной инициализации элементов формы!
     InitializeComponent();
    
     // Определение неизменяемых характеристик окна приложения (формы).
     GetBordersGabarits();
    
     // Начальная коррекция размеров клиентской области окна приложения.
     // "Прямой" вызов метода - обработчика события изменения размеров 
     // окна приложения.
     bForm00_Layout(null, null);
    
     // Определение предельных габаритов окна приложения. 
     SetMinMaxSize();
    
     // Значения синхронизаторов.
     // Неплохо приспособить специальные элементы управления,
     // которые позволяли бы изменять эти значения в интерактивном режиме!
     NX = 50;
     NY = 50;
    
     // Инициализация популяции.
     // Все располагаются в одном месте – в центре клиентской области окна.
     // Одинаковые значения двух последних параметров приводят к тому, что
     // члены популяции синхронно изменяют направление движения. 
     pt = new xPoint[nPT];
     for (i = 0; i < pt.Length; i++)
     {
     pt[i] = new xPoint(
       (int)(this.ClientSize.Width  / (2*rPoint)),
       (int)(this.ClientSize.Height / (2*rPoint)),
        0, //NX, // xPoint.rnd.Next(0, NX+1), // А такие значения нарушают 
        0  //NY  // xPoint.rnd.Next(0, NY+1) // синхронность поведения объектов.
        );
     }
    
     // Процесс пошел!
     mainTimer.Start();
     }
    
     // Определение относительной величины rPoint реализовано как свойство.
     // Замечательная особенность свойства!
     // Оно имеет явную спецификацию возвращаемого значения.
     // И точно такого же типа должен быть единственный параметр value!
     private Size rPointSet
     {            
     set
     { 
     Size s = value;
     rPoint = Math.Sqrt(2.0*s.Width*s.Height) * 0.002;            
     }        
     }
    
     // А вот перегрузить свойство нельзя! Невидимый параметр value 
     // и возвращаемое значение свойства должны быть одного типа. 
     // Именно поэтому МНЕ пришлось вводить пару свойств.
     public double rPointGet
     {
     get
     {
     return rPoint;
     }
     }        
    
     // Обработчик события перерисовки формы.
     // В списке параметров ссылка на объект - инициализатор события,
     // а также ссылка на объект – носитель информации об инкапсуляторе
     // данной поверхности рисования.
     // Способ получения этой информации простой – через свойство Graphics:
     //      Graphics gr = e.Graphics;
     // И знай рисуй себе!
     // Однако эта ссылка нам не понадобится, поскольку мы рисуем
     // не на ПОВЕРХНОСТИ ЭЛЕМЕНТА УПРАВЛЕНИЯ,
     // а в памяти, на ПОВЕРХНОСТИ БИТОВОЙ КАРТЫ. 
     private void bForm00_Paint(object sender, PaintEventArgs e)
     {
     xRedraw(); 
     }
                   
     // Событие Layout возникает при удалении или добавлении дочерних
     // элементов управления,
     // изменении границ элемента управления и других изменениях, 
     // в том числе и изменении размеров формы, которые могут повлиять 
     // на макет элемента.
     // Рекомендуется использовать именно это событие,
     // а не события ..._Resize или ..._SizeChanged. Как сказано 
     // в руководстве, событие Layout возникает в ответ на события
     // ..._Resize и ..._SizeChanged,
     // а также в других ситуациях, когда может понадобиться применение макета.
     private void bForm00_Layout(object sender, LayoutEventArgs e)
     {
     // Использование сразу ДВУХ величин – длины и ширины клиентской 
     // области окна!
     // Вот оптимальное решение проблемы поддержки ПОСТОЯННОГО соотношения
     // характеристик клиентской области  
     // (среднее арифметическое для поддержки равенства сторон).
     // ПЛЮС поправка на размеры рамки окна приложения. 
    
     Size = new System.Drawing.Size
         (
         (ClientSize.Width + ClientSize.Height)/2 + borderWidth,
         (ClientSize.Width + ClientSize.Height)/2 + borderHeight
         );
    
     // После коррекции размеров окна – устанавливаем значение величины 
     // rPoint, которое производится через обращение к свойству rPointSet.   
     rPointSet = this.ClientSize;
    
     // Новая битовая карта под новый размер клиентской области.
     bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
    
     // Объявляется недопустимой конкретная область элемента управления 
     // (здесь форма) и происходит отправка соответствующего сообщения
     // (Paint) элементу управления (форме). При этом значение 
     // параметра (true) 
     // объявляет недопустимыми назначенные элементу управления 
     // дочерние элементы.
     // Для каждого элемента автоматически формируется 
     // объект-представитель
     // класса Graphics, инкапсулирующий поверхность для рисования.
     // Для активизации процесса перерисовки соответствующего 
     // элемента управления требуется объявить метод – обработчик события
     // (в нашем случае это bForm00_Paint).
     this.Invalidate(false); 
     }
    
     // Обработчик события таймера:
     // всем амебам надлежит переопределить собственные координаты и
     // перерисовать картинку! Здесь также можно было бы объявить 
     // недействительной и требующей перерисовки поверхность формы.
     // Это просто: this.Invalidate(false);
     // Однако никто не помешает нам сделать все напрямую, через метод xRedraw.  
     private void mainTimer_Tick(object sender, EventArgs e)
     {
     xPoint.setNextPosition(this, pt);
     xRedraw();
     }
    
     // Перерисовка.
     private void xRedraw()
     {
     // Поверхность для рисования на битовой карте!
     Graphics gr = Graphics.FromImage(bmp);
    
     // Очистить поверхность и закрасить ее в ненавязчивый черный цвет!
     gr.Clear(backColor);
    
     // Нарисовать решетку!
     DrawGreed(gr);
    
     // Нарисовать объекты!
     foreach (xPoint xp in pt)
     {
     // Сообщили кисти цвет объекта... 
     br.Color = xp.xColor;
     // Закрасили объект.
     gr.FillEllipse(br,
                    (float)((xp.p.X * rPoint) - rPoint),
                    (float)((xp.p.Y * rPoint) - rPoint),
                    (float)(2 * rPoint),
                    (float)(2 * rPoint));
     // Сообщили перу цвет объекта... 
     pen0.Color = xp.xColor;
     // Нарисовали контур амебы...
     gr.DrawEllipse(pen0,
                    (float)((xp.p.X * rPoint) - rPoint),
                    (float)((xp.p.Y * rPoint) - rPoint),
                    (float)(2 * rPoint),
                    (float)(2 * rPoint));
     }
    
     // Рисование закончено. Подготовить объект-поверхность к удалению.
     gr.Dispose();
    
     // Отобразить картинку!
     // Это всего лишь модификация свойства Image элемента управления PictureBox. 
     this.mainPictureBox.Image = bmp;
     }
    
     // На поверхности битовой карты (параметр gr) рисуется координатная сетка. 
     private void DrawGreed(Graphics gr)
     {
     float i;
     float w = (float)(this.ClientSize.Width/25.0F);
     float h = (float)(this.ClientSize.Height/25.0F);
     float W = this.ClientSize.Width;
     float H = this.ClientSize.Height;
    
     for (i = h; i < H; i += h)
     {
     gr.DrawLine(this.greedPen, 0, i, W, i);
     }
    
     for (i = w; i < W; i += w)
     {
     gr.DrawLine(this.greedPen, i, 0, i, H);
     }
     }
     }
     }

    Запустили приложение, порадовались отсутствию утомляющего глаза мигания, характерного для непосредственного рисования на поверхности элемента управления... подумали над созданием элементов управления для изменения синхронности перемещения членов амебной популяции.

    GraphicsPath

    GraphicsPath – класс, представляющий последовательность соединенных линий и кривых. Приложения используют контуры для отображения очертаний фигур, заполнения внутренних областей фигур, создания областей отсечения.

    Контур может состоять из любого числа фигур (контуров). Каждая фигура либо составлена из последовательности линий и кривых, либо является геометрическим примитивом. Начальная точка фигуры – первая точка в последовательности соединенных линий и кривых. Конечная точка – последняя точка в последовательности.

    Фигура, состоящая из последовательности соединенных линий и кривых (чьи начальная и конечная точки могут совпадать), является разомкнутой фигурой, если она не замкнута явно. Фигура может быть замкнута явно с помощью метода CloseFigure, который замыкает фигуру путем соединения конечной и начальной точек линией. Фигура, состоящая из геометрического примитива, является замкнутой.

    Для целей заполнения и отсечения (например, если контур визуализируется с помощью метода Graphics.FillPath ) все разомкнутые фигуры замыкаются путем добавления линии от первой точки фигуры к последней.

    Новая фигура начинается неявно, когда создается контур или фигура замыкается. Новая фигура создается явно, когда вызывается метод StartFigure.

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

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

    Конструкторы
    GraphicsPath -конструктор Инициализирует новый экземпляр класса GraphicsPath с перечислением FillMode из Alternate
    Свойства
    FillMode Получает или задает перечисление FillMode, определяющее, как заполняются внутренние области фигур в объекте GraphicsPath
    PathPoints Получает точки в контуре
    PathTypes Получает типы соответствующих точек в массиве PathPoints
    PointCount Получает число элементов в массиве PathPoints или PathTypes
    Методы
    AddArc Присоединяет дугу эллипса к текущей фигуре
    AddBezier Добавляет в текущую фигуру кривую Безье третьего порядка
    AddBeziers Добавляет в текущую фигуру последовательность соединенных кривых Безье третьего порядка
    AddClosedCurve Добавляет замкнутую кривую к данному контуру. Используется кривая фундаментального сплайна, поскольку кривая проходит через все точки массива
    AddCurve Добавляет в текущую фигуру кривую сплайна. Используется кривая фундаментального сплайна, поскольку кривая проходит через все точки массива
    AddEllipse Добавляет эллипс к текущему пути
    AddLine Добавляет отрезок прямой к объекту GraphicsPath
    AddLines Добавляет последовательность соединенных отрезков прямых в конец объекта GraphicsPath
    AddPath Добавляет указанный объект GraphicsPath к данному контуру
    AddPie Добавляет контур сектора к данному контуру
    AddPolygon Добавляет многоугольник к данному контуру
    AddRectangle Добавляет прямоугольник к данному контуру
    AddRectangles Добавляет последовательность прямоугольников к данному контуру
    AddString Добавляет строку текста в данный путь
    ClearMarkers Удаляет все маркеры из данного контура
    Clone Создает точную копию данного контура
    CloseAllFigures Замыкает все незамкнутые фигуры в данном контуре и открывает новую фигуру. Каждая незамкнутая фигура замыкается путем соединения ее начальной и конечной точек линией
    CloseFigure Замыкает текущую фигуру и открывает новую. Если текущая фигура содержит последовательность соединенных линий и кривых, то метод замыкает ее путем соединения начальной и конечной точек линией
    CreateObjRef (унаследовано от Marshal By RefObject ) Создает объект, который содержит всю необходимую информацию для конструирования прокси-сервера, используемого для коммуникации с удаленными объектами
    Dispose Освобождает все ресурсы, используемые объектом GraphicsPath
    Equals (унаследовано от Object ) Определяет, равны ли два экземпляра Object
    Flatten Преобразует каждую кривую в данном контуре в последовательность соединенных отрезков прямых
    GetBounds Возвращает прямоугольник, ограничивающий объект GraphicsPath
    GetHashCode (унаследовано от Object) Служит хэш-функцией для конкретного типа, пригоден для использования в алгоритмах хэширования и структурах данных, например, в хэш-таблице
    GetLastPoint Получает последнюю точку массива PathPoints объекта GraphicsPath
    GetLifetimeService (унаследовано от MarshalByRefObject ) Извлекает служебный объект текущего срока действия, который управляет средствами срока действия данного экземпляра
    GetType (унаследовано от Object ) Возвращает Type текущего экземпляра
    InitializeLifetimeService (унаследовано от MarshalByRefObject ) Получает служебный объект срока действия, для управления средствами срока действия данного экземпляра
    IsOutlineVisible Указывает, содержится ли определенная точка внутри (под) контура объекта GraphicsPath при отображении его с помощью указанного объекта Pen
    IsVisible Определяет, содержится ли указанная точка в объекте GraphicsPath
    Reset Очищает массивы PathPoints и PathTypes и устанавливает FillMode в Alternate
    Reverse Изменяет порядок точек в массиве PathPoints объекта GraphicsPath на противоположный
    SetMarkers Устанавливает маркер на объекте GraphicsPath
    StartFigure Открывает новую фигуру, не замыкая при этом текущую. Все последующие точки, добавляемые к контуру, добавляются к новой фигуре
    ToString (унаследовано от Object ) Возвращает String, который представляет текущий Object
    Transform Применяет матрицу преобразования к объекту GraphicsPath
    Warp Применяет преобразование перекоса, определяемое прямоугольником и параллелограммом, к объекту GraphicsPath
    Widen Заменяет данный контур кривыми, которые окружают область, заполняемую при отображении контура указанным пером
    Защищенные методы
    Finalize Переопределен. См. Object.Finalize.

    В языках C# и C++ для функций финализации используется синтаксис деструктора

    MemberwiseClone (унаследовано от Object ) Создает неполную копию текущего Object

    Region

    Класс Region (Область) предназначается для создания объектов, которые описывают внутреннюю часть графической формы из прямоугольников и фигур, составленных из замкнутых линий. Этот класс не наследуется.

    Область является масштабируемой. Приложение может использовать области для фиксации выходных данных операций рисования. Диспетчер окон применяет области для определения области изображения окон. Эти области называются вырезанными. Приложение может также использовать области в операциях проверки наличия данных, например пересечения точки или прямоугольника с областью. Приложение может заполнять область с помощью объекта Brush.

    Множество пикселей, входящих в состав региона, может состоять из нескольких несмежных участков.

    Список членов класса представляется ниже.

    Открытые конструкторы
    Region -конструктор Инициализирует новый объект Region
    Открытые методы
    Clone Создает точную копию объекта Region
    Complement Обновляет объект Region, чтобы включить часть указанной структуры RectangleF, не пересекающуюся с объектом Region
    CreateObjRef (унаследовано от MarshalByRefObject ) Создает объект, который содержит всю необходимую информацию для создания прокси-сервера, используемого для коммуникации с удаленными объектами
    DisposeEquals Освобождает все ресурсы, используемые объектом Region
    Exclude Обновляет объект Region, чтобы включить часть его внутренней части, не пересекающуюся с указанной структурой Rectangle
    FromHrgn Инициализирует новый объект Region из дескриптора указанной существующей области GDI
    GetBounds Возвращает структуру RectangleF, которая представляет прямоугольник, ограничивающий объект Region на поверхности рисунка объекта Graphics
    GetHashCode (унаследовано от Object ) Служит хэш-функцией для конкретного типа, пригоден для использования в алгоритмах хэширования и структурах данных, например в хэш-таблице
    GetHrgn Возвращает дескриптор Windows для объекта Region в указанном графическом контексте
    GetLifetimeService (унаследовано от MarshalByRefObject ) Извлекает служебный объект текущего срока действия, который управляет средствами срока действия данного экземпляра
    GetRegionData Возвращает объект RegionData, который представляет данные, описывающие объект Region
    GetRegionScans Возвращает массив структур RectangleF, аппроксимирующих объект Region
    GetType (унаследовано от Object ) Возвращает Type текущего экземпляра
    InitializeLifetimeService (унаследовано от MarshalByRefObject ) Получает служебный объект срока действия для управления средствами срока действия данного экземпляра
    Intersect Заменяет объект Region на его пересечение с указанным объектом Region
    IsEmpty Проверяет, имеет ли объект Region пустую внутреннюю часть на указанной поверхности рисунка
    IsInfinite Проверяет, имеет ли объект Region пустую внутреннюю часть на указанной поверхности рисунка
    IsVisible Проверяет, содержится ли указанный прямоугольник в объекте Region
    MakeEmpty Инициализирует объект Region для пустой внутренней части
    MakeInfinite Инициализирует объект Region для бесконечной внутренней части
    ToString (унаследовано от Object ) Возвращает String, который представляет текущий Object
    Transform Преобразует этот объект Region с помощью указанного объекта Matrix
    Translate Смещает координаты объекта Region на указанную величину
    Union Заменяет объект Region на его объединение с указанным объектом GraphicsPath
    Xor Заменяет объект Region на разность объединения и его пересечения с указанным объектом GraphicsPath
    Защищенные методы
    Finalize Переопределен. См. Object.Finalize.

    В языках C# и C++ для функций финализации используется синтаксис деструктора

    MemberwiseClone (унаследовано от Object ) Создает неполную копию текущего Object

    Применение классов GraphicsPath и Region. Круглая форма

    using System;
     using System.Drawing;
     using System.Drawing.Drawing2D;
     using System.Collections;
     using System.ComponentModel;
     using System.Windows.Forms;
    
     namespace StrangeControls
     {
    
     // Объявляется класс – наследник базового класса Form.
     // Наша форма, конечно же, основывается на обычной классической
     // прямоугольной, масштабируемой форме.
     // Прежде всего это означает, что у нее имеется свойство Size,
     // значения которого используются для определения размеров
     // составляющих нашу форму элементов.
     // Наша форма состоит из двух элементов:
     // прямоугольника-заголовка
     // (здесь должны размещаться основные элементы управления формы);
     // эллипсовидной клиентской области с голубой каемочкой.    
    
     public class RoundForm : System.Windows.Forms.Form
     {
     private System.ComponentModel.Container components = null;
     // Объект headSize используется для управления размерами формы.
     private Size headSize;
     // bw – (border width) это переменная,
     // сохраняющая метрические характеристики рамки.
     // В дальнейшем это значение используется для определения 
     // конфигурации нашей формы.
     int bw;
    
     // Ничем не примечательный конструктор...
     public RoundForm()
     {		
     	InitializeComponent();
     }
    
     #region Windows Form Designer generated code
    
     // Required method for Designer support – do not modify
     // the contents of this method with the code editor.
    
     private void InitializeComponent()
     {
     // 
     // RoundForm
     // 
     this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
     this.ClientSize = new System.Drawing.Size(292, 273);
     this.Cursor = System.Windows.Forms.Cursors.Cross;
     this.MinimumSize = new System.Drawing.Size(100, 100);
     this.Name = "RoundForm";
     this.Text = "RoundForm";
     this.Resize += new System.EventHandler(this.RoundForm_Resize);
     }
     #endregion
    
     protected override void Dispose( bool disposing )
     {
      if( disposing )
      {
      if(components != null)
       {
        components.Dispose();
       }
      }
     	base.Dispose( disposing );
     }
    
     // Обработчик события, связанного с изменением формы окна, обеспечивает
     // вызов метода, в котором определяются основные характеристики
     // составляющих формы.
     private void RoundForm_Resize(object sender, System.EventArgs e)
     {
     SetSize();
     }
    
     // Код, определяюший габариты ФОРМЫ – весь здесь...
     // Это определение метрических характеристик ФОРМЫ. 
     protected void SetSize()
     {
      // Всего ничего...
      // На основе соответствующей "классической" формы
      // определяются размеры прямоугольной составляющей (заголовка формы).
      int w = this.Size.Width; 
      bw = (int)((w – this.ClientSize.Width)/2);
      int h = this.Size.Height;
      int bh = h – this.ClientSize.Height – bw;
      headSize = new Size(w,bh);		
     }
    
     // В рамках переопределенной виртуальной функции...
     protected override void OnPaint(PaintEventArgs e)
     {
     // Определяем габариты формы.
     SetSize();
     // Получаем ссылку на графический контекст.
     Graphics gr = this.CreateGraphics(); 
     // Карандаш для отрисовки каемочки.
     Pen pen = new Pen(SystemColors.Desktop,bw);
     // Объект, поддерживающий контуры формы.
     GraphicsPath gp = new GraphicsPath();
     // Контуры формы образуются прямоугольником
     //(его характеристики совпадают с заголовком формы).
     // класс GraphicsPath не имеет метода, который позволял
     // бы непосредственно подсоединять прямоугольные области.
     // Поэтому структура Rectangle предварительно определяется.
     // С эллипсом проще. Он подсоединяется "на лету",
     // без предварительного определения.
     Rectangle rect = new Rectangle(0,0,headSize.Width,headSize.Height);
     gp.AddRectangle(rect);
     gp.AddEllipse(bw,
                   headSize.Height,
                   this.ClientSize.Width,
                   this.ClientSize.Height);
     // Сформировали объект, поддерживающий контуры формы.
     // И на его основе создаем объект, который описывает внутреннюю часть
     // графической формы.
     // В нашем случае она состоит из прямоугольника и эллипса.  
     Region reg = new Region(gp);
     // У любой формы имеется свойство Region.
     // У нашей формы – оно прекрасно. 
     this.Region = reg;
     // Рисуем каемочку...
     gr.DrawEllipse(pen,0,0,this.ClientSize.Width,this.ClientSize.Height);
     // Освобождаем занятые ресурсы.
     gr.Dispose();
     }
     }
     }

    Собственные элементы управления

    В этом разделе обсуждаются некоторые аспекты проблемы построения собственных элементов управления.

    Известно по крайней мере три возможных подхода к разработке новых элементов управления:

  • объединение стандартных элементов управления в группы (составные элементы управления);
  • объявление новых классов, наследующих от существующих элементов управления;
  • написание новых элементов "с нуля".
  • Разработка составных элементов управления предполагает объявление класса, производного от класса UserControl и использование Мастера UserControl, для добавления вложенных элементов управления с последующей настройкой образующих элементов.

    Новый элемент управления может быть построен на основе класса – наследника какого-либо из существующих элементов управления. В этом случае в новом классе удается частично использовать функциональности ранее объявленного класса, возможно, сохраняя при этом внешний вид элемента. Например, можно объявить собственный вариант класса кнопки, который будет наследовать классу Button.

    Написание нового элемента "с нуля" отличается от предыдущего варианта разработки выбором базового класса. В этом случае основываются на классе Control, который не предоставляет потомкам даже элементарного графического интерфейса. Процесс визуализации в этом случае обеспечивается переопределяемым обработчиком события Paint. При этом переопределяется виртуальный метод базового класса OnPaint с единственным аргументом типа PaintEventArgs, который содержит информацию о клиентской области элемента управления. Член этого класса объект типа Graphics – обеспечивает формирование представления элемента управления. Второй член класса – объект типа ClipRectangle – описывает доступную клентскую область элемента управления.

    Следует отметить, что между двумя последними способами определения элементов управления не существует четких границ. В обоих случаях основанием для классификации оказывается объем работы по доопределению и переопределению методов и свойств вновь создаваемого класса элементов управления.

    В рассматриваемом ниже примере определения собственного элемента управления используется объект – представитель класса ImageList. Объекты этого класса предназначаются для сохранения рисунков, которые могут отображаться другими элементами управления. В общем случае этот компонент позволяет написать код для унифицированного каталога рисунков. В нашем варианте он используется для изменения внешнего вида элемента управления. К каждому рисунку можно получить доступ с помощью значения индекса этого рисунка. Отображаемые рисунки имеют один и тот же формат и размер, устанавливаемый в свойстве ImageSize. Таким образом, на основе данного свойства может быть реализован эффект масштабирования элемента управления в смысле изменения его видимых размеров в случае изменения клиентских размеров формы:

    using System;
     using System.Collections;
     using System.ComponentModel;
     using System.Drawing;
     using System.Drawing.Drawing2D;
     using System.Data;
     using System.Windows.Forms;
    
     namespace StrangeControls
     {
    
     // Summary description for RoundButton.
     // Хотя класс RoundButton и объявляется на основе базового
     // класса Button, внешнее представление его
     // объектов-представителей реализуется в переопределяемом
     // методе OnPaint с использованием класса ImageList. 
    
     public class RoundButton : Button
     {
     ImageList imgList;
     // Внешнее представление элемента управления меняется
     // в зависимости от состояния элемента. Это состояние
     // зависит от конкретных событий, происходящих с элементом
     // управления. 
     // Индекс, который используется при изменении внешнего
     // представления элемента управления.
     // Внешний вид элемента управления определяется значением
     // переменной indexB, которая меняет значение в рамках
     // переопределяемых обработчиков событий.
     // Функциональность данного элемента управления задана
     // в классе формы, в виде стандартных (непереопределяемых) обработчиков.  
    
     int indexB; 
    
     public RoundButton():base()
     {
     	indexB = 0;
     	imgList = new ImageList();
     	imgList.Images.Add(Image.FromFile(@"jpg0.jpg"));
     	imgList.Images.Add(Image.FromFile(@"jpg1.jpg"));
     	imgList.Images.Add(Image.FromFile(@"jpg2.jpg"));
     	imgList.Images.Add(Image.FromFile(@"jpg3.jpg"));
     	this.ImageList=imgList;
     	
     }
     // Код, управляющий изменением внешнего вида элемента.
     // Сюда передается управление в результате выполнения метода
     // Refresh(). 
     protected override void OnPaint(PaintEventArgs e)
     {
     GraphicsPath gp = new GraphicsPath();
     gp.AddEllipse(10,10,50,50);
     Region reg = new Region(gp);         
     // Свойству Region присваивается новое значение – новый регион! 
     this.Region = reg;
     e.Graphics.DrawImage(ImageList.Images[indexB],10,10,50,50);
     }
    
     protected override void OnClick(EventArgs e)
     {
     	indexB = 0;
     	this.Refresh();
     	base.OnClick (e);
     }
    
     protected override void OnMouseDown(MouseEventArgs e)
     {
     	indexB = 1;
     	this.Refresh();
     	base.OnMouseDown (e);
     }
    
     protected override void OnGotFocus(EventArgs e)
     {
     	indexB = 0;
     	this.Refresh();
     	base.OnGotFocus (e);
     }
    
     protected override void OnLostFocus(EventArgs e)
     {
     	indexB = 0;
     	this.Refresh();
     	base.OnLostFocus(e);
     }
    
     protected override void OnMouseEnter(EventArgs e)
     {
     	indexB = 2;
     	this.Refresh();
     	base.OnMouseEnter (e);
     }
    
     protected override void OnMouseLeave(EventArgs e)
     {
     	indexB = 3;
     	this.Refresh();
     	base.OnMouseLeave (e);
     }
    
     private void InitializeComponent()
     {
     	// 
     	// RoundButton
     	// 
     }
     }
     }

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

    private void InitializeComponent()
     {
     ::::::::::::::::::::
     // 
     // roundButton1
     // 
     this.roundButton1.Cursor = System.Windows.Forms.Cursors.Cross;
     this.roundButton1.Location = new System.Drawing.Point(136, 8);
     this.roundButton1.Name = "roundButton1";
     this.roundButton1.Size = new System.Drawing.Size(72, 72);
     this.roundButton1.TabIndex = 2;
     this.roundButton1.Text = "roundButton1";
     this.roundButton1.Click += new System.EventHandler(this.roundButton_Click);
     ::::::::::::::::::::
     }
     Сам обработчик события в форме объявлен следующим образом:
    
     private void roundButton_Click(object sender, System.EventArgs e)
     {
      if (imgListindex < imgList.Images.Count–1) imgListindex++;
      else                                       imgListindex = 0;
    
      pictureBox1.Image = imgList.Images[imgListindex];
     }

    Следующий фрагмент кода посвящен разработке составного элемента управления, который представляет собой "батарею" из 16 одинаковых кнопочек, располагаемых на одной панели. Несмотря на внушительное количество составляющих элементов, перед нами один элемент управления с общим единым обработчиком события, связанным с нажатием на одну из 16 кнопочек. Естественно, что реализация единого обработчика требует дополнительных усилий: каждой кнопке назначается один и тот же стандартный обработчик с двумя параметрами. Один из параметров используется для идентификации нажатой кнопки. При нажатии на кнопку происходит изменение состояния этой кнопки, которое кодируется посредством текстового значения (свойства Text ), отображаемого на поверхности кнопки.

    using System;
     using System.Collections;
     using System.ComponentModel;
     using System.Drawing;
     using System.Data;
     using System.Windows.Forms;
    
     namespace By2
     {
    
     // Summary description for ButtonsControl.
    
     public class ButtonsControl : System.Windows.Forms.UserControl
     {
      
     // Required designer variable.
     private Form1 f1;
     private ArrayList bArrList;
     private System.Windows.Forms.Panel panel1;
     private System.Windows.Forms.Button button16;
     private System.Windows.Forms.Button button15;
     private System.Windows.Forms.Button button14;
     private System.Windows.Forms.Button button13;
     private System.Windows.Forms.Button button12;
     private System.Windows.Forms.Button button11;
     private System.Windows.Forms.Button button10;
     private System.Windows.Forms.Button button9;
     private System.Windows.Forms.Button button8;
     private System.Windows.Forms.Button button7;
     private System.Windows.Forms.Button button6;
     private System.Windows.Forms.Button button5;
     private System.Windows.Forms.Button button4;
     private System.Windows.Forms.Button button3;
     private System.Windows.Forms.Button button2;
     private System.Windows.Forms.Button button1;
     public ArrayList parameterList; 
    
     public void SetParent(Form1 fKey)
     {
     f1 = fKey;
     }
    
     private System.ComponentModel.Container components = null;
    
     public ButtonsControl()
     {
     InitializeComponent();
     bArrList = new ArrayList();
     bArrList.Add(button16);
     bArrList.Add(button15);
     bArrList.Add(button14);
     bArrList.Add(button13);
     bArrList.Add(button12);
     bArrList.Add(button11);
     bArrList.Add(button10);
     bArrList.Add(button9);
     bArrList.Add(button8);
     bArrList.Add(button7);
     bArrList.Add(button6);
     bArrList.Add(button5);
     bArrList.Add(button4);
     bArrList.Add(button3);
     bArrList.Add(button2);
     bArrList.Add(button1);
     parameterList = new ArrayList();
     }
    
     private void SetParameterList()
     {
     int i, I = bArrList.Count ;
     parameterList.Clear();
     for (i = 0; i < I;  i++)
     {
     parameterList.Add(int.Parse(((Button)bArrList[i]).Text));		 
     }
     f1.formDecimalValue(parameterList);         
     }
    
     public void SetButtons(ArrayList lst)
     {
     int i, I = lst.Count, J = bArrList.Count;
    
     for (i = 0; i < J; i++)
     {
     ((Button)bArrList[i]).Text = "0";		 
     }
    
     for (i = 0; i < I; i++)
     {
     ((Button)bArrList[i]).Text = ((int)lst[i]).ToString();		 
     }
    
     }
    
      
     // Clean up any resources being used.
    
     protected override void Dispose( bool disposing )
     {
     if( disposing )
     {
     	if(components != null)
     	{
     		components.Dispose();
     	}
     }
     base.Dispose( disposing );
     }
    
     #region Component Designer generated code
      
     // Required method for Designer support – do not modify 
     // the contents of this method with the code editor.
    
     private void InitializeComponent()
     {
     this.panel1 = new System.Windows.Forms.Panel();
     this.button16 = new System.Windows.Forms.Button();
     this.button15 = new System.Windows.Forms.Button();
     this.button14 = new System.Windows.Forms.Button();
     this.button13 = new System.Windows.Forms.Button();
     this.button12 = new System.Windows.Forms.Button();
     this.button11 = new System.Windows.Forms.Button();
     this.button10 = new System.Windows.Forms.Button();
     this.button9 = new System.Windows.Forms.Button();
     this.button8 = new System.Windows.Forms.Button();
     this.button7 = new System.Windows.Forms.Button();
     this.button6 = new System.Windows.Forms.Button();
     this.button5 = new System.Windows.Forms.Button();
     this.button4 = new System.Windows.Forms.Button();
     this.button3 = new System.Windows.Forms.Button();
     this.button2 = new System.Windows.Forms.Button();
     this.button1 = new System.Windows.Forms.Button();
     this.panel1.SuspendLayout();
     this.SuspendLayout();
     // 
     // panel1
     // 
     this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
     this.panel1.Controls.Add(this.button16);
     this.panel1.Controls.Add(this.button15);
     this.panel1.Controls.Add(this.button14);
     this.panel1.Controls.Add(this.button13);
     this.panel1.Controls.Add(this.button12);
     this.panel1.Controls.Add(this.button11);
     this.panel1.Controls.Add(this.button10);
     this.panel1.Controls.Add(this.button9);
     this.panel1.Controls.Add(this.button8);
     this.panel1.Controls.Add(this.button7);
     this.panel1.Controls.Add(this.button6);
     this.panel1.Controls.Add(this.button5);
     this.panel1.Controls.Add(this.button4);
     this.panel1.Controls.Add(this.button3);
     this.panel1.Controls.Add(this.button2);
     this.panel1.Controls.Add(this.button1);
     this.panel1.Location = new System.Drawing.Point(8, 8);
     this.panel1.Name = "panel1";
     this.panel1.Size = new System.Drawing.Size(648, 48);
     this.panel1.TabIndex = 0;
     // 
     // button16
     // 
     this.button16.Location = new System.Drawing.Point(605, 12);
     this.button16.Name = "button16";
     this.button16.Size = new System.Drawing.Size(32, 23);
     this.button16.TabIndex = 146;
     this.button16.Text = "0";
     this.button16.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button15
     // 
     this.button15.Location = new System.Drawing.Point(565, 12);
     this.button15.Name = "button15";
     this.button15.Size = new System.Drawing.Size(32, 23);
     this.button15.TabIndex = 145;
     this.button15.Text = "0";
     this.button15.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button14
     // 
     this.button14.Location = new System.Drawing.Point(525, 12);
     this.button14.Name = "button14";
     this.button14.Size = new System.Drawing.Size(32, 23);
     this.button14.TabIndex = 144;
     this.button14.Text = "0";
     this.button14.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button13
     // 
     this.button13.Location = new System.Drawing.Point(485, 12);
     this.button13.Name = "button13";
     this.button13.Size = new System.Drawing.Size(32, 23);
     this.button13.TabIndex = 143;
     this.button13.Text = "0";
     this.button13.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button12
     // 
     this.button12.Location = new System.Drawing.Point(445, 12);
     this.button12.Name = "button12";
     this.button12.Size = new System.Drawing.Size(32, 23);
     this.button12.TabIndex = 142;
     this.button12.Text = "0";
     this.button12.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button11
     // 
     this.button11.Location = new System.Drawing.Point(405, 12);
     this.button11.Name = "button11";
     this.button11.Size = new System.Drawing.Size(32, 23);
     this.button11.TabIndex = 141;
     this.button11.Text = "0";
     this.button11.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button10
     // 
     this.button10.Location = new System.Drawing.Point(365, 12);
     this.button10.Name = "button10";
     this.button10.Size = new System.Drawing.Size(32, 23);
     this.button10.TabIndex = 140;
     this.button10.Text = "0";
     this.button10.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button9
     // 
     this.button9.Location = new System.Drawing.Point(325, 12);
     this.button9.Name = "button9";
     this.button9.Size = new System.Drawing.Size(32, 23);
     this.button9.TabIndex = 139;
     this.button9.Text = "0";
     this.button9.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button8
     // 
     this.button8.Location = new System.Drawing.Point(285, 12);
     this.button8.Name = "button8";
     this.button8.Size = new System.Drawing.Size(32, 23);
     this.button8.TabIndex = 138;
     this.button8.Text = "0";
     this.button8.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button7
     // 
     this.button7.Location = new System.Drawing.Point(245, 12);
     this.button7.Name = "button7";
     this.button7.Size = new System.Drawing.Size(32, 23);
     this.button7.TabIndex = 137;
     this.button7.Text = "0";
     this.button7.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button6
     // 
     this.button6.Location = new System.Drawing.Point(205, 12);
     this.button6.Name = "button6";
     this.button6.Size = new System.Drawing.Size(32, 23);
     this.button6.TabIndex = 136;
     this.button6.Text = "0";
     this.button6.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button5
     // 
     this.button5.Location = new System.Drawing.Point(165, 12);
     this.button5.Name = "button5";
     this.button5.Size = new System.Drawing.Size(32, 23);
     this.button5.TabIndex = 135;
     this.button5.Text = "0";
     this.button5.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // button4
     // 
     this.button4.Location = new System.Drawing.Point(125, 12);
     this.button4.Name = "button4";
     this.button4.Size = new System.Drawing.Size(32, 23);
     this.button4.TabIndex = 134;
     this.button4.Text = "0";
     this.button4.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button3
     // 
     this.button3.Location = new System.Drawing.Point(85, 12);
     this.button3.Name = "button3";
     this.button3.Size = new System.Drawing.Size(32, 23);
     this.button3.TabIndex = 133;
     this.button3.Text = "0";
     this.button3.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button2
     // 
     this.button2.Location = new System.Drawing.Point(45, 12);
     this.button2.Name = "button2";
     this.button2.Size = new System.Drawing.Size(32, 23);
     this.button2.TabIndex = 132;
     this.button2.Text = "0";
     this.button2.Click += new System.EventHandler (this.buttonX_Click);
     // 
     // button1
     // 
     this.button1.Location = new System.Drawing.Point(5, 12);
     this.button1.Name = "button1";
     this.button1.Size = new System.Drawing.Size(32, 23);
     this.button1.TabIndex = 131;
     this.button1.Text = "0";
     this.button1.Click += new System.EventHandler(this.buttonX_Click);
     // 
     // ButtonsControl
     // 
     this.Controls.Add(this.panel1);
     this.Name = "ButtonsControl";
     this.Size = new System.Drawing.Size(664, 64);
     this.panel1.ResumeLayout(false);
     this.ResumeLayout(false);
    
     }
     #endregion
    
     private void buttonX_Click(object sender, System.EventArgs e)
     {
     if (((Button)sender).Text.Equals("0")) ((Button)sender).Text = "1";
     else                               ((Button)sender).Text = "0";
    
     SetParameterList();
     }
     }
     }
    Вернуться к учебному плану