Extending the PictureEdit control to allow for custom drawing onto the image

I came across this request from DevExpress customer Christopher Todd on the support center requesting that a component be created that allowed for basic drawing/shapes in a WinForms app. While there certainly are a multitude of graphic/imaging libraries available for .NET, many of them are expensive (LeadTools comes to mind) or simply overkill for a simple WinForms business application (DirectX). Specifically, Christopher requested:

It would be nice to have a control that allows basic drawing functionality on the PictureEdit. Basically, a color picker, lines with optional arrow ends, drawing with mouse cursor, basic shapes like square and circle and maybe a highlighter.

I can see the usefulness of such a control. Users could load an image into the PictureEdit control and draw some shapes or lines onto the image for whatever reason. My idea was to create a PictureEdit descendant control which could be dragged onto a form at design time and which internally handled drawing those shapes onto itself at runtime. The developer shouldn’t have to do any customization–it should just work.

My initial creation offers 4 methods of drawing onto the “canvas”. There are three built-in shapes (ellipse, rectangle and line) and a freehand drawing mode which uses the mouse cursor as a pencil. To activate them, I added two DXEditMenu items to the PictureEdit’s built-in context menu:

/// <summary>
/// Gets the Picture Menu for this PictureEditCanvas control
/// </summary>
protected override PictureMenu Menu
{
    get { return dxPopupMenu; }
}
/// <summary>
/// On create control event handler
/// </summary>
protected override void OnCreateControl()
{
    base.OnCreateControl();
    dxPopupMenu = CreatePictureMenu();

    //Add in our custom DXMenuItems
    DXMenuItem drawingTools = new DXMenuItem("Drawing Tools", new EventHandler(OnDrawingToolsClick));
    drawingTools.BeginGroup = true;
    drawingTools.Image = PictureEditDrawing.Properties.Resources.pictureshapeoutlinecolor_16x16;
    dxPopupMenu.Items.Add(drawingTools);

    DXMenuItem saveImage = new DXMenuItem("Save Image", new EventHandler(OnSaveImageClick));
    saveImage.Image = Menu.Items[6].Image;
    dxPopupMenu.Items.Add(saveImage);

}   //End the OnCreateControl() method

Nothing special going on here. This gives us something like this:

PictureEdit custom context menu
PictureEdit custom context menu

Clicking on the Drawing Tools menu item gives us our toolset, which perhaps we can extend in a future version:

Drawing tools dialog
Drawing tools dialog

Here is where your end user will pick which tool they want to use on the PictureEdit canvas. Different tools have slightly different options (start & end caps only apply to lines, and only the rectangle and ellipse can be filled). Once the user clicks OK, the PictureEdit turns into “Drawing Mode” where it tracks the mouse buttons and movement and paints the shape/drawing onto the canvas.

The final part of the control involves saving your new masterpiece to the harddrive. Using the PictureEdit’s built-in save method won’t cut it for this. The PictureEdit itself has no concept of the shapes you’ve drawn on top of it–it would only save the Image object stored internally. To overcome this, we take a snapshot of the control and save that:

/// <summary>
/// Saves the modified PictureEditCanvas image
/// </summary>
/// <param name="FileName">File name for the saved image</param>
private void SaveModifiedImage(string FileName)
{
    using (Bitmap imageBMP = new Bitmap(Width, Height))
    {
        DrawToBitmap(imageBMP, Bounds);
        imageBMP.Save(FileName);

    }   //End the using() statement

}   //End the SaveModifiedImage() method

This is really a quick overview of how it works, but the internals of the whole project are just basic GDI drawing commands which can be studied anywhere. Some important points to note are that the control should force itself to redraw when the mouse is moved (and the user is actually drawing something) via the Invalidate method. We also want to take care to dispose of GDI objects wherever possible, because Paint events can be fired very often which increases the result of a memory leak or an exception as GDI handles increase.

As always, I’ve provided the full sample code and a basic test project showing the control in action. Download here: PictureEditDrawing

PS. Forgive the code formatting in this post–WordPress doesn’t seem to be very friendly to formatted C# code anymore.

Extending the PictureEdit control to allow for custom drawing onto the image

One thought on “Extending the PictureEdit control to allow for custom drawing onto the image

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s