Click here to Skip to main content
Click here to Skip to main content

A Graphics Drawing Tool by using WPF

By , 23 Jun 2011
 

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)

About the Author

Lewis Liu L
Software Developer
Australia Australia
Member
If you think this article is useful, please donate using paypal:
https://www.paypal.com/au/webapps/mpp/make-online-payments
 
by using my email: yyiu002@hotmail.com

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionhow can I rotate a shapememberferfr14 Nov '11 - 18:42 
AnswerRe: how can I rotate a shapememberLewis Liu (yyiu002)14 Nov '11 - 22:11 
QuestionDali would be proudmvpSacha Barber23 Jun '11 - 22:15 
GeneralMy vote of 1memberPhil J Pearson21 Jun '11 - 3:21 
QuestionCan you please include a screenshot?groupAmarnath S20 Jun '11 - 2:08 
QuestionThis is not an article!memberPerry Bruins19 Jun '11 - 18:51 
AnswerRe: This is not an article!memberLewis Liu (yyiu002)19 Jun '11 - 23:03 
GeneralRe: This is not an article!memberSlacker00720 Jun '11 - 0:16 

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 23 Jun 2011
Article Copyright 2011 by Lewis Liu L
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid