Êíèãà: C# 2008 Programmer

Creating the Project Using Visual Studio 2008

Creating the Project Using Visual Studio 2008

Using Visual Studio 2008, create a new Silverlight project using C# and name it Signature (see Figure 19-63).


Figure 19-63

If you have installed the Microsoft Silverlight Tools Beta 1 for Visual Studio 2008 tool, you should see Silverlight in the Project Types list in the New Project dialog.

You will be asked how you want to host your application. Select the second option (Generate an HTML test page to host Silverlight within this project), and click OK (see Figure 19-64).


Figure 19-64

Populate Page.xaml as follows:

<UserControl
 xmlns="http://schemas.microsoft.com/client/2007"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Width="400" Height="300">
 <Canvas>
  <Canvas
   x:Name="SigPad" Width="404" Height="152"
   Canvas.Left="8" Canvas.Top="9"

 Background="#FFF4F60C">

   <Rectangle
    Width="404" Height = "152"
    Fill="#FFF1F8DB" Stroke="#FF000000"
    StrokeThickness="3"/>
  </Canvas>
 </Canvas>
</UserControl>

The page should now look like Figure 19-65.


Figure 19-65

Capturing the Signature

As the user uses the mouse (or stylus if he/she is using a tablet PC) to write on the control, the series of points it makes on the control will be saved. There will be three events of concern to you:

MouseLeftButtonDown — Fired when the left mouse button is clicked

MouseMove — Fired when the mouse moves

MouseLeftButtonUp — Fired when the left mouse button is released

Figure 19-66 shows what happens when you write the character "C". When the left mouse button is clicked, the MouseLeftButtonDown event is fired, followed by a series of MouseMove events as the mouse moves counterclockwise, and then finally the MouseLeftButtonUp event is fired when the mouse's left button is released. As the mouse moves, the series of points made by it are joined together.


Figure 19-66

The points touched by the mouse between the MouseLeftButtonDown and MouseLeftButtonUp events are saved as a series of continuous points (called a line). For example, the character "C" is made up of one line (assuming that you did not release the left mouse button while drawing it), while the character "t" is made up of two lines — one horizontal and one vertical (see Figure 19-67).


Figure 19-67

The points making up an individual line are saved in a generic List object. The individual lines in each character are also saved in a generic List object, as Figure 19-68 shows.


Figure 19-68

Coding the Application

In Page.xaml.cs (see Figure 19-69), declare the following member variables:

public partial class Page : UserControl {
 private bool MouseDown = false;
 private Point _previouspoint;
 private List<Point> _points;
 private List<List<Point>> _lines = new List<List<Point>>();


Figure 19-69

Add the following highlighted lines to the Page() constructor:

public Page() {
 InitializeComponent();
 //---wire up the event handlers---
 SigPad.MouseLeftButtonDown += new
  MouseButtonEventHandler(SigPad_MouseLeftButtonDown);
 SigPad.MouseLeftButtonUp += new
  MouseButtonEventHandler(SigPad_MouseLeftButtonUp);
 SigPad.MouseMove += new
  MouseEventHandler(SigPad_MouseMove);
}

The MouseLeftButtonDown event is fired when the user clicks on the left mouse button. Here you interpret it as the beginning of the signature signing process. Code the MouseLeftButtonDown event handler of SigPad as follows:

//---fired when the user clicks on the Signature pad---

void SigPad_MouseLeftButtonDown(
 object sender, MouseButtonEventArgs e) {
 //---record that the mouse left button is pressed---
 MouseDown = true;
 //---create a new instance of _points and _lines to
 // record all the points drawn---
 _points = new List<Point>();
 //---save the current point for later use---
 _previouspoint = e.GetPosition(SigPad);
 //---add the point---
 _points.Add(_previouspoint);
}

The MouseLeftButtonUp event is fired when the user releases the left mouse button. You interpret that as the end of the signature signing process. Code the MouseLeftButtonUp event handler of SigPad as follows:

//---fired when the user let go of the left mouse button---
void SigPad_MouseLeftButtonUp(
 object sender, MouseButtonEventArgs e) {
 //---user has let go of the left mouse button---
 MouseDown = false;
 //---add the list of points to the current line---
 _lines.Add(_points);
}

The MouseMove event is fired continuously when the user moves the mouse. Here, you draw a line connecting the previous point with the current point. Code the MouseMove event handler of SigPad as follows:

//---fired when the left mouse button is moved---
void SigPad_MouseMove(object sender, MouseEventArgs e) {
 //---if left mouse button is pressed...---
 if (MouseDown) {
  //---add the current point---
  var currentPoint = e.GetPosition(SigPad);
  _points.Add(currentPoint);
  //---draws a line connecting the previous
  // point and the current point---
  Line line = new Line() {
   X1 = _previouspoint.X,
   Y1 = _previouspoint.Y,
   X2 = currentPoint.X,
   Y2 = currentPoint.Y,
   StrokeThickness = 2,
   Stroke = new SolidColorBrush(Colors.Black)
  };
  //---add the line to the signature pad---
  SigPad.Children.Add(line);
  //---saves the current point for later use---
  _previouspoint = currentPoint;
 }
}

Press F5 to test the application. Use your mouse to draw on the web page (see Figure 19-70).


Figure 19-70

Saving the Signature to Isolated Storage

This section explains how to store the coordinates of the signature using isolated storage. This technique is useful if you need to persist information on the client side, such as backing up the signature that the user has signed.

Using the same project created in the previous section, add the following highlighted code to Page.xaml:

<UserControl
 xmlns="http://schemas.microsoft.com/client/2007"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Width="400" Height="300">
 <Canvas>
  <Canvas Width="404" Height="152"
   Canvas.Left="8" Canvas.Top="9" Background="#FFF4F60C">
   <Rectangle Width="404" Height="152" Fill="#FFF1F8DB"
    Stroke="#FF000000" StrokeThickness="3"/>
  </Canvas>
  <Canvas>
   <Canvas Width="97" Height="26"
    Canvas.Left="315" Canvas.Top="168">
    <Rectangle Width="96" Height = "25"
     Stroke="#FF000000" Fill="#FFE6EBFF"
     RadiusX="3" RadiusY="3" StrokeThickness="3"/>
    <TextBlock Width="34" Height="20"
     TextWrapping="Wrap" Canvas.Left="32"
     Canvas.Top="1" Text ="Save"/>
   </Canvas>
   <Canvas Width="97" Height="26"
    Canvas.Left="214" Canvas.Top="168">
    <Rectangle Width="96" Height="25"
     Stroke="#FF000000" Fill="#FFE6EBFF"
     RadiusX="3" RadiusY="3" StrokeThickness="3"/>
    <TextBlock Width="37" Height="20" TextWrapping="Wrap"
     Canvas.Left="30" Canvas.Top="1" Text="Load"/>
   </Canvas>
   <Canvas Width="97" Height="26"
    Canvas.Left="113" Canvas.Top="168">
    <Rectangle Width="96" Height="25" Stroke="#FF000000"
     Fill="#FFE6EBFF" RadiusX="3" RadiusY="3"
     StrokeThickness="3"/>
    <TextBlock Width="37" Height="20" TextWrapping="Wrap"
     Canvas.Left="30" Canvas.Top="1" Text="Clear"/>
   </Canvas>
   <TextBlock Width="404" Height="20" Text="[Status]"
    TextWrapping="Wrap" Canvas.Left="8" Canvas.Top="198"
    OpacityMask="#FF000000"/>
  </Canvas>
 </Canvas>
</UserControl>
Page.xaml
should now look like Figure 19-71.


Figure 19-71

In Page.xaml.cs, import the following namespaces:

using System.IO.IsolatedStorage;
using System.IO;

Add the following lines to the Page() constructor:

public Page() {
 InitializeComponent();
 //---wire up the event handlers---
 SigPad.MouseLeftButtonDown += new
  MouseButtonEventHandler(SigPad_MouseLeftButtonDown);
 SigPad.MouseLeftButtonUp += new
  MouseButtonEventHandler(SigPad_MouseLeftButtonUp);
 SigPad.MouseMove += new
  MouseEventHandler(SigPad_MouseMove);
 //---wire up the event handlers---
 btnSave.MouseLeftButtonDown += new
  MouseButtonEventHandler(btnSave_MouseLeftButtonDown);
 btnLoad.MouseLeftButtonDown += new
  MouseButtonEventHandler(btnLoad_MouseLeftButtonDown);
 btnClear.MouseLeftButtonDown += new
  MouseButtonEventHandler(btnClear_MouseLeftButtonDown);
}

Define the GetSignatureLines() function so that the coordinates of the signature can be converted from a List object to a string:

//---returns the signature as a series of lines---
private string GetSignatureLines() {
 System.Text.StringBuilder sb = new
  System.Text.StringBuilder();
 //---for each line---
 for (int i = 0; i <= _lines.Count - 1; i++) {
  //---for each point---
  foreach (Point pt in _lines[i]) {
   sb.Append(pt.X + "," + pt.Y + "|");
  }
  sb.Append("n");
 }
 return sb.ToString();
}

Code the MouseLeftButtonDown event handler for the Save button so that the signature can be saved to isolated storage:

//---Save button---
void btnSave_MouseLeftButtonDown(
 object sender, MouseButtonEventArgs e) {
 //---save into isolated storage---
 IsolatedStorageFile isoStore =
  IsolatedStorageFile.GetUserStoreForApplication();
 IsolatedStorageFileStream isoStream =
  new IsolatedStorageFileStream("IsoStoreFile.txt",
  FileMode.Create, isoStore);
 StreamWriter writer = new StreamWriter(isoStream);
 //---writes the lines to file---
 writer.Write(GetSignatureLines());
 txtStatus.Text = "Signature saved!";
 writer.Close();
 isoStream.Close();
}

Define the DrawSignature() subroutine so that the signature can be reproduced from a string representing a collection of lines:

//---draws the signature---
private void DrawSignature(string value) {
 _lines = new List<List<Point>>();
 //---split into individual lines---
 string[] lines = value.Split('n');
 //---for each individual line---
 for (int i = 0; i <= lines.Length - 2; i++) {
  //---split into individual points---
  string[] ps = lines[i].Split('|');
  _points = new List<Point>();
  //---for each point---
  for (int j = 0; j <= ps.Length - 2; j++) {
   string[] xy = ps[j].Split(',');
   _points.Add(new Point(
    (Convert.ToDouble(xy[0])),
    Convert.ToDouble(xy[1])));
  }
  _lines.Add(_points);
 }
 //---draws the signature---
 for (int line = 0; line <= _lines.Count - 1; line++) {
  _points = (List<Point>)_lines[line];
  for (int i = 1; i <= _points.Count - 1; i++) {
   Line sline = new Line() {
    X1 = _points[i - 1].X,
    Y1 = _points[i - 1].Y,
    X2 = _points[i].X,
    Y2 = _points[i].Y,
    StrokeThickness = 2,
    Stroke = new SolidColorBrush(Colors.Black)
   };
   SigPad.Children.Add(sline);
  }
 }
}

Code the MouseLeftButtonDown event handler for the Load button so that the series of signature lines can be loaded from isolated storage:

//---Load button---
void btnLoad_MouseLeftButtonDown(
 object sender, MouseButtonEventArgs e) {
 IsolatedStorageFile isoStore =
  IsolatedStorageFile.GetUserStoreForApplication();
 IsolatedStorageFileStream isoStream =
  new IsolatedStorageFileStream("IsoStoreFile.txt",
  FileMode.Open, isoStore);
 StreamReader reader = new StreamReader(isoStream);
 //---read all lines from the file---
 string lines = reader.ReadToEnd();
 //---draws the signature---
 DrawSignature(lines);
 txtStatus.Text = "Signature loaded!";
 reader.Close();
 isoStream.Close();
}

Code the MouseLeftButtonDown event handler for the Clear button so that the signature can be cleared from the drawing pad:

//---Clear button---
void btnClear_MouseLeftButtonDown(
 object sender, MouseButtonEventArgs e) {
 _lines = new List<List<Point>>();
 _points = new List<Point>();
 //---iteratively clear all the signature lines---
 int totalChild = SigPad.Children.Count - 2;
 for (int i = 0; i <= totalChild; i++) {
  SigPad.Children.RemoveAt(1);
 }
 txtStatus.Text = "Signature cleared!";
}

Press F5 to test the application. You can now sign and then save the signature. You can also load the saved signature (see Figure 19-72).


Figure 19-72

Saving the Signature to Web Services

One of these signatures isn't a lot of good unless you can send it to a Web Service. This section shows you how to do that.

Using the same project created in the previous section, add a new Web Site project to the current solution (see Figure 19-73).


Figure 19-73

Select ASP.NET Web Site, and name the project SignatureWebSite.

Add a new Web Service item to the Web Site project, and use its default name of WebService.asmx (see Figure 19-74).


Figure 19-74

In the WebService.cs file, add the following lines:

using System;
using System.Collections;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.IO;
using System.Web.Script.Services;
/// <summary>
/// Summary description for WebService /// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {
 ...
 ...
}

Define the following two web methods:

[WebMethod]
public bool SaveSignature(string value) {
 try {
  File.WriteAllText(Server.MapPath(".") +
   @"Signature.txt", value);
  return true;
 } catch (Exception ex) {
  return false;
 }
}
[WebMethod]
public string GetSignature() {
 string fileContents;
 fileContents = File.ReadAllText(
  Server.MapPath(".") + @"Signature.txt");
 return fileContents;
}

The SaveSignature() function saves the values of the signature into a text file. The GetSignature() function reads the content of the text file and returns the content to the caller.

In the Signature project, add a service reference (see Figure 19-75).


Figure 19-75

Click the Discover button and then OK (see Figure 19-76).


Figure 19-76

In Page.xaml.cs, modify the Save button as follows:

//---Save button---
void btnSave_MouseLeftButtonDown(
 object sender, MouseButtonEventArgs e) {
 try {
  ServiceReference1.WebServiceSoapClient ws = new
   Signature.ServiceReference1.WebServiceSoapClient();
  //---wire up the event handler when the web service returns---
  ws.SaveSignatureCompleted += new

   EventHandler<Signature.ServiceReference1.SaveSignatureCompletedEventArgs>(ws_SaveSignatureCompleted);

  //---calls the web service method---
  ws.SaveSignatureAsync(GetSignatureLines());

 } catch (Exception ex) {

  txtStatus.Text = ex.ToString();
 }
}

Here, you send the signature to the Web service asynchronously. When the Web Service call returns, the ws_SaveSignatureCompleted event handler will be called.

Code the ws_SaveSignatureCompleted event handler as follows:

void ws_SaveSignatureCompleted( object sender,
 Signature.ServiceReference1.SaveSignatureCompletedEventArgs e) {
 txtStatus.Text = "Signature sent to WS!";
}

In Page.xaml.cs, code the Load button as follows:

//---Load button---
void btnLoad_MouseLeftButtonDown(
 object sender, MouseButtonEventArgs e) {
 try {
  ServiceReference1.WebServiceSoapClient ws = new
   Signature.ServiceReference1.WebServiceSoapClient();
  //---wire up the event handler when the web service
  // returns---
  ws.GetSignatureCompleted +=
   new EventHandler<Signature.ServiceReference1.GetSignatureCompletedEventArgs>(ws_GetSignatureCompleted);
  //---calls the web service method---
  ws.GetSignatureAsync();

 } catch (Exception ex) {

  txtStatus.Text = ex.ToString();
 }
}

Here, you call the Web service to retrieve the saved signature. When the Web Service call returns, the ws_GetSignatureCompleted event handler will be called.

Code the ws_GetSignatureCompleted event handler as follows:

void ws_GetSignatureCompleted( object sender,
 Signature.ServiceReference1.GetSignatureCompletedEventArgs e) {
 txtStatus.Text = "Signature loaded from WS!";
 DrawSignature(e.Result);
}

Save the Signature project. In Solution Explorer, right-click on the SignatureWebSite project and select Add Silverlight Link (see Figure 19-77).


Figure 19-77

This causes Visual Studio 2008 to copy the relevant files from the Silverlight project onto the current project. Use the default values populated and click Add (see Figure 19-78).


Figure 19-78

Notice that a new folder named ClientBin, containing the Signature.xap file, is added to the project (see Figure 19-79).


Figure 19-79

In Solution Explorer, right-click the SignatureWebSite project and select Set as Startup Project (see Figure 19-80).


Figure 19-80

Select SignatureTestPage.aspx, and press F5 to test the project. You can now save the signature to the Web Service as well as load the saved signature from the Web Service (see Figure 19-81).


Figure 19-81

Îãëàâëåíèå êíèãè

Îãëàâëåíèå ñòàòüè/êíèãè

Ãåíåðàöèÿ: 1.293. Çàïðîñîâ Ê ÁÄ/Cache: 3 / 1
ïîäåëèòüñÿ
Ââåðõ Âíèç