Click here to Skip to main content
15,891,513 members
Articles / Desktop Programming / WPF

A Graphics Drawing Tool by using WPF

Rate me:
Please Sign up or sign in to vote.
3.33/5 (5 votes)
23 Jun 2011GPL32 min read 42.8K   3K   10   8
Graphics Drawing Tool by WPF

Introduction

This is an article about WPF and its drawing tool.

The code structure is similar as that of my other article at code project, the link is at:

WinForm Versions of GraphicsDrawingTool.aspx

Background

To understand this article, you need to understand a few WPF technologies. Concept such as DrawingContext, FrameworkElement class, and their usages, and of course how to write XAML GUI stuff.

Using the code

This project first create a tool box, like following:

wpf2.jpg

Then user can draw their selected shape on screen, like following:

wpf1.jpg

The drawing then can be exported as xml file or jpg file.

<?xml version="1.0" encoding="utf-8"?>
<ShapeList xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>" xmlns:xsd="<a href="http://www.w3.org/2001/XMLSchema">http://www.w3.org/2001/XMLSchema</a>">
  <ShapeList>
    <LeShape xsi:type="LeRectangle">
      <ShowBorder>true</ShowBorder>
      <LeBorderColor>
        <A>255</A>
        <R>0</R>
        <G>0</G>
        <B>0</B>
      </LeBorderColor>
      <BorderWidth>1</BorderWidth>
      <Rect>
        <X>300</X>
        <Y>157</Y>
        <Width>79</Width>
        <Height>65</Height>
      </Rect>
      <LeFromColor>
        <A>30</A>
        <R>255</R>
        <G>0</G>
        <B>0</B>
      </LeFromColor>
      <LeToColor>
        <A>30</A>
        <R>255</R>
        <G>255</G>
        <B>255</B>
      </LeToColor>
      <LightAngle>225</LightAngle>
      <Fill>true</Fill>
    </LeShape>
    <LeShape xsi:type="RoundRectShape">
      <ShowBorder>true</ShowBorder>
      <LeBorderColor>
        <A>255</A>
        <R>0</R>
        <G>0</G>
        <B>0</B>
      </LeBorderColor>
      <BorderWidth>1</BorderWidth>
      <Rect>
        <X>174</X>
        <Y>230</Y>
        <Width>84</Width>
        <Height>74</Height>
      </Rect>
      <LeFromColor>
        <A>255</A>
        <R>0</R>
        <G>0</G>
        <B>0</B>
      </LeFromColor>
      <LeToColor>
        <A>255</A>
        <R>127</R>
        <G>255</G>
        <B>212</B>
      </LeToColor>
      <LightAngle>225</LightAngle>
      <Fill>true</Fill>
      <Radius>10</Radius>
    </LeShape>
    <LeShape xsi:type="ZoneShape">
      <ShowBorder>true</ShowBorder>
      <LeBorderColor>
        <A>255</A>
        <R>0</R>
        <G>0</G>
        <B>0</B>
      </LeBorderColor>
      <BorderWidth>1</BorderWidth>
      <Rect>
        <X>132</X>
        <Y>97</Y>
        <Width>90</Width>
        <Height>84</Height>
      </Rect>
      <LeFromColor>
        <A>30</A>
        <R>255</R>
        <G>0</G>
        <B>0</B>
      </LeFromColor>
      <LeToColor>
        <A>30</A>
        <R>255</R>
        <G>255</G>
        <B>255</B>
      </LeToColor>
      <LightAngle>225</LightAngle>
      <Fill>true</Fill>
      <TextField>
        <ShowBorder>true</ShowBorder>
        <LeBorderColor>
          <A>255</A>
          <R>0</R>
          <G>0</G>
          <B>0</B>
        </LeBorderColor>
        <BorderWidth>1</BorderWidth>
        <Rect>
          <X>237</X>
          <Y>112</Y>
          <Width>58</Width>
          <Height>22</Height>
        </Rect>
        <LeFromColor>
          <A>30</A>
          <R>255</R>
          <G>0</G>
          <B>0</B>
        </LeFromColor>
        <LeToColor>
          <A>30</A>
          <R>255</R>
          <G>255</G>
          <B>255</B>
        </LeToColor>
        <LightAngle>225</LightAngle>
        <Fill>true</Fill>
        <Caption>Shape 2</Caption>
        <LeTextFont>
          <Size>10</Size>
          <Name>Tahoma</Name>
          <Style>Regular</Style>
        </LeTextFont>
        <LeTextColor>
          <A>255</A>
          <R>255</R>
          <G>0</G>
          <B>0</B>
        </LeTextColor>
        <TextSize>10</TextSize>
      </TextField>
      <Caption>Shape 2</Caption>
    </LeShape>
  </ShapeList>
</ShapeList>

This xml file then can be reopened later by this project, end user can edit their drawings again.

Following is the explaination of this project's source code.

The project first create a canvas on GUI by using following lines:

<Border Margin="10" CornerRadius="3" Grid.Row="1" Grid.Column="1" Background="Beige">
   <Border.BitmapEffect>
      <DropShadowBitmapEffect />
   </Border.BitmapEffect>
   <Canvas Margin="3" x:Name="DrawingCanvas" Background="AliceBlue" Opacity="1" Visibility="Visible">
   <local:CustomRender Canvas.Top="0" Canvas.Left="0" x:Name="shapeCollection">
    <local:CustomRender.BitmapEffect>
      <DropShadowBitmapEffect />
    </local:CustomRender.BitmapEffect>
   </local:CustomRender>
   </Canvas>
</Border>

The code above first create a Border, with a drop shadow, Border was inside a Grid control, so it will fill the grid's cell. Then what's inside of this border, it's a canvas control, what's inside this Canvas is just one framework element, our DLL (CustomRender), it is just one element, then we use this element's DrawingContext, draw all our shapes manually. The DrawingContext is like WinForm's Graphics object.

Our customrender is just a framework element, it only accept visuals objects. Most importantly it implemented following 2 functions:

// Provide a required override for the VisualChildrenCount property.
        protected override int VisualChildrenCount
        {
            get { return childrens.Count; }
        }
       // Provide a required override for the GetVisualChild method.
        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= childrens.Count)
            {
                throw new ArgumentOutOfRangeException();
            }
            return childrens[index];
        }  

Then at our code, we only need to add visual object to this collections of visual object, .netframework will render this CustomRender object for us.

We used reflection to add shape to our controller class, first only create a shape, then add shape's visual object to above CustomRender class.

Point pt = e.GetPosition(myCanvas);

ConstructorInfo constructor = myTool.GetConstructor(new Type[] { typeof(Point) });
CurShape = constructor.Invoke(new object[] { pt }) as LeShape;


shapeCollection.AddObject(CurShape.myVisual);

When we want to draw this Shape, we can call following method at anytime:

DrawingContext dc = myVisual.RenderOpen();
Draw(dc);

if (selected)
{
   if (bounds.Width > 5 && bounds.Height >5)
   {
       DrawPoints(dc, bounds);
   }
}
dc.Close();

RenderOpen method of DrawingVisual will open a DrawingContext for us, then we can Draw our object, if shape is selected, then I draw several track points for it. After all these, we have to call DrawingContext Close method, this to tell we have finished drawing of this visual.

This the principles of WPF version of my drawing tool, if you are intertested you can get more information on my WinForms version of this drawing tool as well.


Points of Interest

Did you learn anything interesting/fun/annoying while writing the code? Did you do anything particularly clever or wild or zany?

History

Keep a running update of any changes or improvements you've made here.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
Australia Australia
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 can I rotate a shape Pin
ferfr14-Nov-11 18:42
ferfr14-Nov-11 18:42 
AnswerRe: how can I rotate a shape Pin
Lewis Liu L14-Nov-11 22:11
Lewis Liu L14-Nov-11 22:11 
QuestionDali would be proud Pin
Sacha Barber23-Jun-11 22:15
Sacha Barber23-Jun-11 22:15 
GeneralMy vote of 1 Pin
Phil J Pearson21-Jun-11 3:21
Phil J Pearson21-Jun-11 3:21 
QuestionCan you please include a screenshot? Pin
Amarnath S20-Jun-11 2:08
professionalAmarnath S20-Jun-11 2:08 
QuestionThis is not an article! Pin
Perry Bruins19-Jun-11 18:51
Perry Bruins19-Jun-11 18:51 
AnswerRe: This is not an article! Pin
Lewis Liu L19-Jun-11 23:03
Lewis Liu L19-Jun-11 23:03 
GeneralRe: This is not an article! Pin
Slacker00720-Jun-11 0:16
professionalSlacker00720-Jun-11 0:16 

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.