Создание простого конструктора бланков на C#
Автор: Мухаммед Эльшейми (Mohammad Elsheimy) Конструктор бланков предоставляет пользователям гибкие возможности создания бланков, отчетов, счетов, счетов-фактур и других пользовательских документов. Введение Сегодня мы собираемся создать простое приложение, фактически простое средство создания бланков. Это средство предоставляет пользователю гибкие возможности разработки собственных бланков, отчетов, счетов, счетов-фактур и рецептов (на выбор пользователя.) В этой статье все отчеты, счета, счета-фактуры, рецепты и т. д. мы будем называть просто бланками. Поэтому нам понадобится дать определение бланка. Бланк — это просто пустая страница (т. е. шаблон), содержащая элементы бланка. Например, шаблон резюме — это бланк, содержащий много элементов (имя, дата рождения, адрес, и т. д.). Приходный кассовый ордер — это бланк, содержащий несколько элементов (дата, сумма, на чей счет отнесено, кем получено и т. д.). Мы подробно разберем это средство. Начнем с очень простого системного анализа и схемы приложения. Затем перейдем к кодированию. На самом деле я не архитектор и, думаю, никогда им не буду. Поэтому НЕ ругайте меня за этот плохой анализ. Он — просто иллюстрация, призванная дать цельное понимание того, для чего предназначено это приложение. Проблема Пользователь привязан к макетам бланков, разработанных для пользователя дизайнером. Но ему нужна возможность создавать собственные бланки и/или изменять бланки, определенные в приложении. Требования Требования пользователя Ниже перечислены типовые пользовательские требования:
Функциональные требования Общими функциональными требованиями (требованиями к разработчику) являются следующие:
Решение После разработки требований к проекту и анализа сложного дизайна системы мы получаем хороший план для нашего проекта, который будет называться Geming SISC (Sheet Infrastructure Components, компоненты инфраструктуры списка). Этот проект будет создан с помощью C# и .NET 2.0 (или, конечно же, более поздних версий.) Снимки экранов Ниже приведены конечные снимки экранов приложения. На рис. 1 показан бланк приходного кассового ордера с надписями, полями и линиями. На рис. 2 показан простой шаблон резюме, разработанный с использованием только нескольких надписей и картинки. В левой области приложения перечислены текущие бланки, сгруппированные по категориям. Как известно, другие компоненты системы моли заполнить эти поля правильными данными. Разработка компонентов На рис. 3 показаны три компонента нашей системы. Тремя компонентами нашей системы, Geming SISC, являются:
Схемы классов Одной из основных целей системы является ее расширяемость. Следует учитывать гибкую иерархию классов, а также создание производных элементов управления (т. е. наследование) для других внешних объектов. Ниже показана иерархия классов для элементов управления бланка и линеек. Как можно видеть, базовым является класс System.Windows.Forms.Control. Это позволяет вставлять элементы управления бланка и линеек в форму Windows или элемент управления Windows. На следующем рисунке, рис. 5, показана иерархия классов элементов бланка (формально называемых фигурами.) Как можно видеть, базовым классом для всех фигур является абстрактный класс Geming.Sisc.Infrastructure.ShapeBase, наследуемый от класса System.Windows.Forms.Control. Все остальные фигуры являются производными от ShapeBase. Были созданы две редактируемые фигуры: TextBoxShape, выглядящая как текстовое поле Windows, и LabelShape, выглядящая как обычная надпись Windows. Оба класса являются производными от абстрактного класса EditableShapeBase. Другими фигурами являются: BoxShape (прямоугольник), LineShape (линия), ImageShape (картинка) и CheckBoxShape (флажок). Все классы являются сериализуемыми (реализуют интерфейс System.Runtime.Serialization.ISerializable), поэтому их можно легко преобразовать в XML и поместить в базу данных. Для простоты мы разработали только фигуры прямоугольника, линии, картинки, флажка и две редактируемые фигуры (или элементы бланка.) Пользователь может пойти дальше и создать любые нужные ему фигуры. Кроме того, можно создать более специфические элементы, такие как CurrencyField (поле валюты), DateField (поле данных) и т. д. Более подробные схемы классов, показывающие, например, члены классов, см., открыв код приложения. Схема базы данных В своей простоте база данных определяется как следующая схема: Обратите внимание, что все операции с данными выполняются в базе данных с помощью хранимых процедур. Столбец Shape.Value является столбцом типа xml, чтобы упростить обработку XML-данных в будущем. Характеристики Вот некоторые характеристики (т.е. атрибуты) бланка (некоторые из них представлены свойствами):
Кроме того, ниже перечислены некоторые характеристики фигуры (элемента бланка):
Предыстория Вот несколько приемов, используемых в этой системе.
В некоторых случаях мы используем пользовательское рисование. Следовательно, мы воспользуемся помощью классов System.Drawing, конкретно класса System.Drawing.Graphics. В некоторых фигурах, подражающих существующим элементам управления Windows (таким как текстовое поле и флажок), классы из пространства имен System.Windows.Forms.VisualStyles помогут нам отразить в наших элементах управления визуальные стили Windows. Кроме того, класс System.Windows.Forms.ControlPaint используется для рисования границ и прямоугольников выделения.
Каждый элемент управления в нашем проекте (бланк, линейки и фигуры) содержит свойство качества, определяющее качество рисования (низкое, среднее и высокое.) Чтобы это работало, мы будем использовать некоторые свойства объекта System.Drawing.Graphics, например свойства, связанные со сглаживанием и функцией устранения неровностей.
Все сериализованные объекты должны быть помечены атрибутом System.SerializableAttribute. Настроить процесс сериализации нам поможет пространство имен System.Runtime.Serialization. Основным интерфейсом, который позволил бы нам настроить процесс сериализации, является интерфейс System.Runtime.Serialization.ISerializable (реализованный во всех сериализуемых классах.) Обратите внимание, что нам следует добавить конструктор десериализации, чтобы получить правильную десериализацию.
Базой данных является клиентская база данных SQL Server, в которой все операции выполняются с помощью хранимых процедур. Система использует двухуровневую архитектуру, то есть она обращается к базе данных напрямую, используя только три объекта: подключение, команда и чтение данных.
Для расширения поддержки режима конструктора мы создали настраиваемую службу конструктора для класса Sheet, наследуемого от класса System.Windows.Forms.Design.ParentControlDesigner, чтобы позволить использовать вложенные элементы управления в объекте Sheet в режиме конструктора. Выделенные фрагменты кода В этом разделе мы рассмотрим важные блоки кода, которые могут оказаться интересны.
Ниже приведен код для процедуры OnPaint(), переопределяемой только классом ShapeBase. Пример кода 1. Пример кода метода ShapeBase.OnPaint()
Эта функция сначала вызывает функцию GraphicsManager.SetQuality(), определяющую атрибуты качества объекта Graphics. Мы скоро вернемся к этой функции. Затем функция рисует границу элемента управления, используя класс System.Windows.Forms.ControlPaint. Наступает интересный момент. Функция вызывает виртуальную функцию PaintShape(), которую производный класс переопределяет, предоставляя собственные процедуры рисования. Например, у класса TextBoxShape есть своя переопределенная функция PaintShape() override. Пример кода 2. Пример кода метода TextBoxShape.PaintShape()
Затем функция OnPaint() рисует рамку выделения, если фигура в данный момент выбрана. Перед завершением своей работы эта функция вызывает функцию ControlPaint.DrawSizeGrip(), чтобы нарисовать захват изменения размера, который пользователь сможет использовать для изменения размера фигуры.
В нашей библиотеке Geming.Sisc.Infrastructure мы создали вспомогательный класс GraphicsManager, содержащий только одну функцию, SetQuality(). У этой функции два входных параметра, графический объект и качество, которое нужно задать для этого объекта. Ниже приведен код для функции SetQuality(). Пример кода 3. Пример кода метода GraphicsManager.SetQuality()
|