Drawing with Ink in ASP.NET using Silverlight

Posted by: Suprotim Agarwal , on 2/24/2009, in Category Silverlight 2, 3, 4 and 5
Views: 52335
Abstract: In this article, we will create an Ink Sketch pad application using ASP.NET and Silverlight where users will be able to draw strokes into the pad. We will also see how to add Silverlight to an existing ASP.NET application.
Drawing with Ink in ASP.NET using Silverlight
 
In this article, we will create an Ink Sketch pad application using ASP.NET and Silverlight where users will be able to draw strokes into the pad. We will also see how to add Silverlight to an existing ASP.NET application.
The article is composed into two sections. The first section will cover how to add Silverlight into an existing ASP.NET application. The second section shows how to draw with Ink in Silverlight using the InkPresenter control which contains events to collect and process strokes.





Add Silverlight into an existing ASP.NET Web application
To add Silverlight into an existing ASP.NET application, follow these steps:
Step1: Assuming you already have an ASP.NET application, drag and drop the Silverlight control from the toolbox
Silverlight ToolBox
Note: If you cannot find the Silverlight control in the toolbox, you have not installed the add-ins for Visual Studio. Read my article over here.
Step 2: Once you drag drop the Silverlight control to the asp.net page (default.aspx), your page should resemble markup similar to the following (in addition to the asp.net controls you have)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
 
<%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls"
    TagPrefix="asp" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Silverlight ID="Silverlight1" runat="server" Height="100px" Width="100px">
        </asp:Silverlight>
    </div>
    </form>
</body>
</html>
 
Step 3: Now go to File > Add > New Project > Choose ‘Silverlight’ as the project type and choose the name as ‘InkXaml’ and click Ok. You will get a dialog similar to the following:
Link Silverlight
Click Ok. On clicking ok, you will see that a ‘ClientBin’ folder and 2 Silverlight test pages; one .aspx and the other .HTML gets created in your Web project. A Silverlight project also gets added. Open this new test .aspx page (InkXamlTestPage.aspx). You will find that the ‘Source’ attribute of the Silverlight control is set to a .xap file. I would suggest you to use this new page as the test page. Once everything works fine, you can then copy this markup to the Default.aspx.
It’s time to now code the Inking functionality using the InkPresenter control.
Drawing with Ink in Silverlight
Step 4: Go to the Silverlight project, open the Page.xaml and the following markup to the GridLayout.
<UserControl x:Class="InkXaml.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="250" />
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
 
        <Border Background="Gray" CornerRadius="20" x:Name="borderInk" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" >
<InkPresenter x:Name="inkP" Background="Transparent" Cursor="Stylus"                       MouseLeftButtonDown="inkP_MouseLeftButtonDown"                     MouseLeftButtonUp="inkP_MouseLeftButtonUp"                       MouseMove="inkP_MouseMove"/>
        </Border>
 
        <Button x:Name="btnErase" Content="Eraser" Grid.Column="0" Grid.Row="1" Height="40" Width="100" Click="btnErase_Click" />
        <Button x:Name="btnDraw" Content="Draw" Grid.Column="1" Grid.Row="1" Height="40" Width="100" Canvas.Left="100" Click="btnDraw_Click" />
    </Grid>
</UserControl>
We have added the InkPresenter control along with two buttons to toggle between the Draw and Erase mode. Notice that the Cursor is set to ‘Stylus’ which displays a dot using which we can draw on the Pad surface. We are also handling a few mouse events on the InkPresenter, which I will explain in a bit.
Step 5: In Page.xaml.cs or .vb, add the following code:
C#
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Ink;
 
namespace InkXaml
{
public partial class Page : UserControl
{
    private Stroke _stroke = null;
    private StylusPointCollection eraserPoints;
    private InkMode _mode = InkMode.Draw;
 
    public enum InkMode
    {
        Draw,
        Erase
    }
 
    public Page()
    {
        InitializeComponent();
 
    }
 
    private void inkP_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        inkP.CaptureMouse();
        if (_mode == InkMode.Draw)
        {
            _stroke = new Stroke();
            _stroke.DrawingAttributes.Color = Colors.White;
            _stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkP));
            inkP.Strokes.Add(_stroke);
        }
        if (_mode == InkMode.Erase)
        {
            eraserPoints = new StylusPointCollection();
            eraserPoints = e.StylusDevice.GetStylusPoints(inkP);
        }
    }
 
    private void inkP_MouseMove(object sender, MouseEventArgs e)
    {
        if (_mode == InkMode.Draw)
        {
            if (null != _stroke)
            {
                _stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkP));
            }
        }
        if (_mode == InkMode.Erase)
        {
            if (null != eraserPoints)
            {
                eraserPoints.Add(e.StylusDevice.GetStylusPoints(inkP));
                StrokeCollection hits = inkP.Strokes.HitTest(eraserPoints);
                for (int cnt = 0; cnt < hits.Count; cnt++)
                {
                    inkP.Strokes.Remove(hits[cnt]);
                }
            }
        }
    }
 
    private void inkP_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _stroke = null;
        eraserPoints = null;
        inkP.ReleaseMouseCapture();
    }
 
 
    private void btnErase_Click(object sender, RoutedEventArgs e)
    {
        inkP.Cursor = Cursors.Eraser;
        _mode = InkMode.Erase;
    }
 
    private void btnDraw_Click(object sender, RoutedEventArgs e)
    {
        inkP.Cursor = Cursors.Stylus;
        _mode = InkMode.Draw;
    }
}
}
 
VB.NET
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Ink
 
Namespace InkXaml
Partial Public Class Page
      Inherits UserControl
      Private _stroke As Stroke = Nothing
      Private eraserPoints As StylusPointCollection
      Private _mode As InkMode = InkMode.Draw
 
      Public Enum InkMode
            Draw
            [Erase]
      End Enum
 
      Public Sub New()
            InitializeComponent()
 
      End Sub
 
      Private Sub inkP_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
            inkP.CaptureMouse()
            If _mode = InkMode.Draw Then
                  _stroke = New Stroke()
                  _stroke.DrawingAttributes.Color = Colors.White
                  _stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkP))
                  inkP.Strokes.Add(_stroke)
            End If
            If _mode = InkMode.Erase Then
                  eraserPoints = New StylusPointCollection()
                  eraserPoints = e.StylusDevice.GetStylusPoints(inkP)
            End If
      End Sub
 
      Private Sub inkP_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
            If _mode = InkMode.Draw Then
                  If Nothing IsNot _stroke Then
                        _stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkP))
                  End If
            End If
            If _mode = InkMode.Erase Then
                  If Nothing IsNot eraserPoints Then
                        eraserPoints.Add(e.StylusDevice.GetStylusPoints(inkP))
                        Dim hits As StrokeCollection = inkP.Strokes.HitTest(eraserPoints)
                        For cnt As Integer = 0 To hits.Count - 1
                              inkP.Strokes.Remove(hits(cnt))
                        Next cnt
                  End If
            End If
      End Sub
 
      Private Sub inkP_MouseLeftButtonUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
            _stroke = Nothing
            eraserPoints = Nothing
            inkP.ReleaseMouseCapture()
      End Sub
 
 
      Private Sub btnErase_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            inkP.Cursor = Cursors.Eraser
            _mode = InkMode.Erase
      End Sub
 
      Private Sub btnDraw_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            inkP.Cursor = Cursors.Stylus
            _mode = InkMode.Draw
      End Sub
End Class
End Namespace
As shown in the code above, we use the InkPresenter control to display a collection of ink strokes. A Stroke is a collection of stylus points. The InkPresenter control does not have the capability to create strokes on its own. So we have to create strokes programmatically by handling the 3 mouse events MouseLeftButtonDown, MouseLeftButtonUp and MouseMove on the InkPresenter control.
We start by declaring 3 private variables:
·         _stroke to store and display the collection points as the user interacts with the application
·         eraserPoints to store a collection of stylus points collected since the last mouse events
·         _mode which is an enumeration variable to represent the current mode of the stylus i.e erase or draw.
When the mouse is pressed down on the InkPresenter, we handle the MouseLeftButtonDown event. Here we check for the InkMode and create a new Stroke instance with the current StylusPoints and save it in our private stroke collection variable _stroke.
When the user moves the mouse/stylus keeping it pressed, we check if the _stroke collection is not null and add the StylusPoint objects collected from the MouseEventArgs, to the stroke collection. If the InkMode is Erase, we first retrieve the stylus points (eraserpoints) collected since the last mouse event and then use HitTest to gather the intersection of eraserpoints  into a StrokeCollection object. We then loop through the stroke collection and remove the occurrences of the eraser points.
When the user releases the mouse, we end the drawing by completing the newly added stroke. The two buttons are to toggle the Cursor and InkMode to reflect the Drawing or Erasing operation.
To sum it up, the entire action occurs in 3 events. You create a new stroke in the memory and add it to the InkPresenter's StrokeCollection in the MouseLeftButtonDown event. You then add Stylus Points to the stroke when the user moves his mouse and finally complete the stroke when the user releases the mouse. You can even use a Stylus as in a Tablet PC.
Step 6: Now right click on the InkXaml project and build the project. You will see that the ClientBin folder now contains the InkXaml.xap file after the build process is over. It’s time to test the application. Right click ‘InkXamlTestPage.aspx’ > View in Browser. The display will look similar to the following. Use the Gray area to draw lines and shapes as you desire
InkPad
Clicking on the Eraser button changes the cursor to the shape of an Eraser and you can now erase lines not desired. I have removed a line as displayed below:
Ink Eraser
Step 7: With the application tested, it’s time to move the markup from the test page to the actual page, in our case Default.aspx
After moving the markup, the default.aspx will now look similar to the following:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
 
<%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls"
    TagPrefix="asp" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
        <div style="height:100%;">
            <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/InkXaml.xap" MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />
        </div>
    </form>
</body>
</html>
 
Note: If you just realized that you have created a master piece drawing on the inkpad :) and now want to save it, use the technique explained over here: http://www.thedatafarm.com/blog/2008/01/31/ConvertingSilverlightInkPresenterImagesToAPNGFile.aspx
That’s it. Run and test the Default.aspx page. We can now use Ink in ASP.NET Pages!
I hope you liked the article and I thank you for viewing it. The source code of this article can be downloaded from here

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of DotNetCurry, DNC Magazine for Developers, SQLServerCurry and DevCurry. He has also authored a couple of books 51 Recipes using jQuery with ASP.NET Controls and The Absolutely Awesome jQuery CookBook.

Suprotim has received the prestigious Microsoft MVP award for ten consecutive times. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.

Get in touch with him on Twitter @suprotimagarwal or at LinkedIn



Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by wali on Wednesday, July 8, 2009 6:13 AM
thanks alot!! you have solved my problem!!!! :D:D:D:D
i tried to add a silverlight application to asp.net page..but failed to do it..googled it for hours. but thanx to you! :)
Comment posted by Suprotim Agarwal on Friday, July 17, 2009 2:51 AM
Wali: Glad you found it useful.
Comment posted by karthick.R on Monday, July 4, 2011 4:39 AM
this
Comment posted by karthick.R on Monday, July 4, 2011 4:39 AM
this
Comment posted by sdf on Friday, March 7, 2014 6:01 AM
sdsdg
Comment posted by Aarsha on Sunday, July 27, 2014 6:01 AM
Thank u....this helped me to drawing in silverlight...Please help me to save this.

Categories

JOIN OUR COMMUNITY

POPULAR ARTICLES

C# .NET BOOK

C# Book for Building Concepts and Interviews

Tags

JQUERY COOKBOOK

jQuery CookBook