Click here to Skip to main content
15,917,632 members
Articles / Programming Languages / Visual Basic

AGE, Another Graphic Engine in .NET

Rate me:
Please Sign up or sign in to vote.
4.96/5 (36 votes)
10 May 2007CPOL8 min read 137.6K   5.9K   170   34
A library that allows some GDI+ manipulation at runtime in an easy way


This library lets you manipulate graphic objects in your app at runtime.

Sample Image - another_graphic_engine_2.png


Sometime ago, I read that someone had asked for a way to drag items over a panel. Since I had the same problem (all began with the designer of MyNeoReport project) I tried to solve this in a generic way, so that the system could be used in different applications without efforts.

AGE supports items dragging, snap-to-grid, multiselection, layers and much more.
AGE is growing fast; if I were you I would keep an eye on this project.

Principal Subjects

  • GraphicItem: The item to be drawn
  • Painter: The class that does the "dirty work" of painting
  • GraphicDocument: The class that collects all the items to be drawn on a single surface
  • Canvas: The control that shows the drawing

Why This Set of Class?

Q: Why do I need an RendererBase and why don't I put the Render() method directly to the GraphicItem class?
A: Because I need more abstraction.
In this way I separate the logical item from the actor of the rendering.
I can virtually have the same renderer for different items or I can choose a different renderer for a single item.

Q: Why is the GraphicDocument a separate class from Canvas? I could add all the items to draw directly to the Canvas.
A: Same reason of the first question: the GraphicDocument is the logical items aggregation, it is the document, the canvas is the surface on which the document is drawn.
And again, in this way, I could have the same document open on more canvas.

Ok, Let's Start... How Does It Work?

Q: How can I make my own graphic document?
A: Ok, let's define a complete new custom document:

class CustomDocument : GraphicDocument
// define here your document properties

// define a custom item: an ellipse.
class Ellipse : GraphicItem
    Color _foreColor = Color.Blue;

    public Ellipse()
        Painter = new EllipsePainter();

    public Color ForeColor
        get{ return _foreColor; }
        set{ _foreColor = value; }

// define the ellipse painter
class EllipsePainter : Painter
    // how the ellipse is painted...
    protected override void Paint(Graphics g)
        Ellipse ellipse = (Ellipse)Item;
        Pen pen = new Pen(ellipse.ForeColor);
        g.DrawEllipse(pen, Item.Bounds);


canvas1.Document = new CustomDocument();
// add a new ellipse to the default layer
canvas1.Document.AddItem(new Ellipse());

From release, you can also use ScriptAge to define your custom graphic item at runtime:

ScriptedItem triangle = new ScriptedItem();
// Of course: it doesn't make much sense to hard code the script :)
// Rather you would load it from a separate text file or a string resource.
triangle.Script = "stroke: Polygon\n",
                  "pen: #7070ff, 2!\n",
                  "brush: gradient, #0000ff, #000000ff, (0; 0.5) (1; 1)\n",
                  "points: (0; 0.5) (1; 0.0) (1; 1)\n"

See the References section below for more details.

Limits in Items Drawing

  • Your GDI+ fantasy

How Can You Contribute?

If you think this article and the project published are interesting and/or useful, you can help me maintain it in many ways:

  • Giving new ideas
  • Notifying/fixing bugs
  • Implementing new features
  • Diffusing the project
  • Putting a credit to this project in your application's About Box
  • Voting for this article
  • Visiting my Web site and its forum
  • Visiting my Web site and making a little contribution (this would be a great incentive)


Thanks to Itai Bar-Haim for the help and enhancements provided.

Wish List

  • [] Zoom (Thanks to Itai Bar-Haim)
  • [ D] Porting to Linux+Mono
  • [ B] ItemEnter/ItemLeave events
  • [] Ability to load an items library
  • [] GraphicItem [Browsable(false)]Min/MaxSize
  • [] SelectionPainter to customize the rendering of the selection "border" of selected items
  • [] LoadFrom() and SaveTo() working on Stream, so you can include the document as an assembly resource
  • [] Layers
  • [] A good serialization way to save graphic documents
  • [] Ability to save the drawing as an image file
  • [] Toolbar Icon
  • Ability to print the drawing
  • Undo/Redo
  • Clipboard Copy/Past of selected items
  • Management of physical unit measures (cm, mm, meters, inches...) on screen and on other devices such as a printer
  • ... Anything else?

I need some help... any suggestions?



For any questions or suggestions, please go to my Web site forum.

I'm sorry, this release is not 100% compatible with C but, you should not have problems with it. I changed some property names, so I chose to change the version number, and you need to recompile applications that use AGE engine.

If you have some documents to be loaded, you must edit them with Notepad and replace the properties that were renamed (listed below).

Sample Image - age_scripteditem_3.png
  • Added:
    • GraphicItem.RotationCenter, GraphicItem.RotationCenterRelativeTo that let you define the center of the rotation angle
    • Stroke.RotationCenter, with ScriptAGE you can define a rotation point for each single stroke
    • Canvas QueryCursor event that lets you know about the cursor state and lets you set your custom cursor
    • Image Stroke
    • Text Scripted Stroke beta (not fully working yet)
    • Theme and DefaultTheme classes that let you define the canvas appearance (Thanks to Itai Bar-Haim)
    • Canvas.Zoom property (Thanks to Itai Bar-Haim)
    • Drag handlers on each side of selected items (Thanks to Itai Bar-Haim)
  • Fixed:
    • Canvas.Cursor is now readonly and reflects the cursor state at runtime
    • Drag is only allowed with left mouse button (right and center buttons can be used for other purposes)
    • GraphicItem.Angle were renamed in GraphicItem.RotationAngle
    • Stroke.Angle were renamed in Stroke.RotationAngle
    • Canvas.GridSize was renamed to Canvas.SnapGridSize to avoid conflicts with the Visual Studio designer GridSize property
    • ScriptAGE fixed for stroke and item properties
    • A lot of other bugs
  • Tested on Linux Ubuntu 7.4 + Mono the engine works well, the designer needs some workaround since Mono does not completely support the TreeView (not implemented TreeView.Sort(), TreeView.NodeMouseDoubleClick event, TreeView.NodeMouseClick() event) Release C

In this release, I enhanced ScriptAge again.
ScriptAge is 100% compatible with the release.

Sample Image - age_scripteditem_2.png
  • Now ScriptAge can define strokes formed by multiple figures
  • This lets you make a stroke formed by curves and lines together
  • Added path, radial, elliptic brush types
  • Brushes now can have more than 2 colors
  • Scriptage is now extensible: you can define your own PaintStroke class
  • Your custom stroke can define your accepted tokens overriding the PaintStroke.ParseToken() method
  • Added the PathStroke class Release B

From now, I'll mark the AGE engine with the AssemblyDescriptionAttribute to indicate the sub-release. This is because from, I signed the assembly with a strong name and I can no longer modify the release number for compatibility reasons.

In this release, I enhanced ScriptAge (see the References section).
ScriptAge is 100% compatible with the release.

  • Now ScriptAge supports comments, image token, multiline tokens, and more
  • Some minor ScriptAge and Canvas fixes
  • Added Canvas ItemMouseEnter and ItemMouseExit events
  • Fixed a bug with the Drag & Drop of controls on the Canvas at design-time

This release let me add an heavy improvement to the flexibility of this library allowing you to define an item directly at runtime.

Sample Image - age_scripteditem.png

  • Added ScriptedItem class that lets you define the graphic with a little script
  • A bunch of code clean up

This time, the major change is the possibility to write custom items into separate libraries that can be loaded by the document at runtime.

Sample Image - another_graphic_engine_libraries.png
  • Added:
    • virtual GraphicItem.PointIsOverMe() that lets you define if a point lies over the item
    • Size GraphicItem.MinSize that lets you define the minimum size of an item
    • class SelectionPainter and GraphicItem.SelectionPainter that lets you customize the selection border of your item
    • virtual Document.LoadLibrary() that lets you import GraphicItems from external DLLs
    • GraphicLayer Canvas.ActiveLayer
    • bool Canvas.AllowUserEditItems and bool Canvas.AllowUserScrollCanvas that lets you decide if the user can manipulate canvas content and how
    • Painter.GetPoint(), Painter.GetSize(), Painter.FlipPoint() and Painter.FlipRectangle()
    • Painter.OnItemBoundsChanged()
    • Something else that I don't remember
  • The test project starts becoming a real designer

This release focuses on layers feature. It was a real challenge and it is still in beta (It works! I'm thinking of a more OOP solution).

Sample Image - another_graphic_engine_layers.png
  • Added Document.Groups that define item groups and the wrapper GraphicDocument.Layers
  • Removed the ContextMenuStrip from canvas because is not a flexible solution for the applications that implement canvas and it is not supported by Mono
  • Canvas.OffsetX and Canvas.OffsetY are now Point Canvas.Offset
  • RendererBase was renamed in Painter, so it is more similar to the framework naming
  • Usual fixes and minor changes

This release focuses on the ability of saving the document on disk, but there were dozens of collateral enhancement on this:

  • I did a big review of class infrastructure. Now I introduced these generic base classes:
    • Document
    • DocumentItem

This lets you derive what kind of document you want and lets you save it to disk without additional code.
GraphicDocument now inherits from Document and GraphicItem inherits from DocumentItem

  • Serialization is done by some classes that I won't describe in this article, also because they are not complete and may change soon
  • Enhanced and fixed cursor and the selection way on canvas
  • Improved refresh speed
  • Added virtual methods to let you decide to accept or cancel an action on an item or on the document:
Document.OnAddingToDocument(DocumentActionEventArgs e)
Document.OnRemovingFromDocument(DocumentActionEventArgs e)
Document.OnAddedToDocument(DocumentActionEventArgs e)
Document.OnRemovedFromDocument(DocumentActionEventArgs e)

DocumentItem.OnAddingToDocument(DocumentActionEventArgs e)
DocumentItem.OnAddedToDocument(DocumentActionEventArgs e)
DocumentItem.OnRemovingFromDocument(DocumentActionEventArgs e)
DocumentItem.OnRemovedFromDocument(DocumentActionEventArgs e)
  • Added:
GraphicDocument.SaveImage(string fileName, ImageFormat format)
GraphicDocument.GraphicItems // this is a subset of Document.Items
Document.SaveTo(string fileName)
Document.LoadFrom(string fileName)

  • Removed the Renderer.RenderType enum: now it is the Canvas that decides how and what to render
  • Added properties:
    • Canvas.DrawInvisibleItems
    • Canvas.DrawDocumentBounds
  • Document.Items is now a GraphicItemCollection
  • Canvas.SelectedItems is now a GraphicItemCollection
  • Canvas.ItemMouseDoubleClick event is now Canvas.ItemDoubleClick
  • Added Canvas.ItemClick event
  • Various minor modifications and fixes that I don't remember

  • This is the first public release


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Web Developer
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

Questionhow to use your designer? Pin
Southmountain9-Sep-22 10:04
Southmountain9-Sep-22 10:04 
GeneralDocument scaling Pin
SimonasB29-Jul-09 23:04
SimonasB29-Jul-09 23:04 
QuestionCome si elimina/rimpicciolisce il bordo degli oggetti grafici ? Pin
lelmarir11-Sep-08 0:56
lelmarir11-Sep-08 0:56 
Generalgood job Pin
walter224-Apr-08 12:22
walter224-Apr-08 12:22 
Generaldownload Pin
JossGP19-Nov-07 4:31
JossGP19-Nov-07 4:31 
GeneralRe: download Pin
Dreaden21-Jan-08 21:23
Dreaden21-Jan-08 21:23 
Generalanother problem Pin
honey0371_yy18-Jun-07 2:10
honey0371_yy18-Jun-07 2:10 
GeneralRe: another problem Pin
Fabio Zanetta18-Jun-07 5:35
Fabio Zanetta18-Jun-07 5:35 
GeneralRe: another problem Pin
honey0371_yy18-Jun-07 16:35
honey0371_yy18-Jun-07 16:35 
GeneralRe: another problem Pin
Fabio Zanetta18-Jun-07 21:17
Fabio Zanetta18-Jun-07 21:17 
GeneralRe: another problem Pin
honey0371_yy19-Jun-07 23:16
honey0371_yy19-Jun-07 23:16 
GeneralRe: another problem Pin
Fabio Zanetta19-Jun-07 23:50
Fabio Zanetta19-Jun-07 23:50 
GeneralNeoDataType.snk is missing Pin
honey0371_yy17-Jun-07 22:54
honey0371_yy17-Jun-07 22:54 
GeneralRe: NeoDataType.snk is missing Pin
Fabio Zanetta17-Jun-07 23:53
Fabio Zanetta17-Jun-07 23:53 
GeneralNeoDataType.Graphic.Christmas is still missing Pin
michael. zhao12-Feb-07 17:11
michael. zhao12-Feb-07 17:11 
GeneralRe: NeoDataType.Graphic.Christmas is still missing Pin
Fabio Zanetta13-Feb-07 0:49
Fabio Zanetta13-Feb-07 0:49 
GeneralOttimo! Pin
carloqueirolo11-Jan-07 3:45
carloqueirolo11-Jan-07 3:45 
GeneralRe: Ottimo! Pin
Fabio Zanetta11-Jan-07 7:16
Fabio Zanetta11-Jan-07 7:16 
GeneralRe: Ottimo! Pin
carloqueirolo11-Jan-07 21:27
carloqueirolo11-Jan-07 21:27 
GeneralRe: Ottimo! Pin
Fabio Zanetta12-Jan-07 4:36
Fabio Zanetta12-Jan-07 4:36 
GeneralChristmas Pack is missing Pin
Mc Gwyn17-Dec-06 2:30
Mc Gwyn17-Dec-06 2:30 
GeneralRe: Christmas Pack is missing Pin
Fabio Zanetta17-Dec-06 2:40
Fabio Zanetta17-Dec-06 2:40 
GeneralSimilar Project Pin
Ri Qen-Sin12-Dec-06 23:01
Ri Qen-Sin12-Dec-06 23:01 
GeneralRe: Similar Project Pin
Fabio Zanetta12-Dec-06 23:08
Fabio Zanetta12-Dec-06 23:08 
GeneralRe: Similar Project Pin
Ri Qen-Sin13-Dec-06 7:17
Ri Qen-Sin13-Dec-06 7:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.