Silverlight for Mobile on Windows Phone 7 InkPresenter fun

After installing the Windows Phone Developer Tools this is a simple test for a bit of fun using Silverlight for Mobile for the first time to capturing user strokes using the InkPresenter.

  1. In Visual Studio 2010 Press File –> New Project –> Silverlight for Windows Phone –> Windows Phone Application
  2. Creating a Silverlight for Mobile Application

    Creating a Silverlight for Mobile Application

  3. Add an InkPresenter and two buttons Undo and Redo to the to the content Grid
  4.  

          <!--ContentGrid is empty. Place new content here-->
            <Grid x:Name="ContentGrid" Grid.Row="1">
                <InkPresenter  Name="inkTest" Background="White" Margin="0,0,0,62" />
                <Button Name="btnUndo" Content="Undo" Grid.Row="1" Height="72" HorizontalAlignment="Left" Margin="44,584,0,0" VerticalAlignment="Top" Width="160" Click="btnUndo_Click" Background="#FF933A3A" />
                <Button Name="btnRedo" Content="Redo" Height="72" HorizontalAlignment="Left" Margin="272,584,0,0" VerticalAlignment="Top" Width="160" Grid.Row="1" Click="btnRedo_Click" Background="#FF933A3A" />
            </Grid>
  5. On the InkPresenter, named inkTest in this example, Add Event handlers for MouseMove, MouseLeftButtonDown, MouseLeftButtonUp to capture the movement from the user
  6.             inkTest.MouseMove += new MouseEventHandler(inkTest_MouseMove);
                inkTest.MouseLeftButtonDown += new MouseButtonEventHandler(inkTest_MouseLeftButtonDown);
                inkTest.MouseLeftButtonUp += new MouseButtonEventHandler(inkTest_MouseLeftButtonUp);
  7. To capture the mouse movements and turn them into Strokes on the InkPresenter the corresponding EventHandlers and member variables are as follows
  8. private Stroke _currentStroke;
    
    private void inkTest_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _currentStroke = null;
    }
    
    private void inkTest_MouseMove(object sender, MouseEventArgs e)
    {
        if (_currentStroke != null)
            _currentStroke.StylusPoints.Add(GetStylusPoint(e.GetPosition(inkTest)));
    }
    
    private void inkTest_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        inkTest.CaptureMouse();
        _currentStroke = new Stroke();
        _currentStroke.StylusPoints.Add(GetStylusPoint(e.GetPosition(inkTest)));
        _currentStroke.DrawingAttributes.Color = Colors.Blue;
        inkTest.Strokes.Add(_currentStroke);
    }
    
    private StylusPoint GetStylusPoint(Point position)
    {
        return new StylusPoint(position.X, position.Y);
    }
  9. And since its difficult to draw with a mouse I want to be able to undo and redo some of my Strokes I use a simple Stack so implement the following EventHandlers for the Undo and Redo buttons
  10.         private Stack _removedStrokes = new Stack();
    
            private void btnUndo_Click(object sender, RoutedEventArgs e)
            {
                if (inkTest.Strokes != null && inkTest.Strokes.Count > 0)
                {
                    _removedStrokes.Push(inkTest.Strokes.Last());
                    inkTest.Strokes.RemoveAt(inkTest.Strokes.Count - 1);
                }
            }
    
            private void btnRedo_Click(object sender, RoutedEventArgs e)
            {
                if (_removedStrokes != null && _removedStrokes.Count > 0)
                {
                    inkTest.Strokes.Add(_removedStrokes.Pop());
                }
            }
  11. And the final result is :)
  12. InkPresenter on Windows Phone 7

    InkPresenter on Windows Phone 7

This demonstrated a simple application that was faster to code then to blog about and that even with an undo button I am still hopeless at drawing :) . Try implementing the same functionality in the .NET Compact Framework :)

Next posts will look at

  • Reworking this application to use MVVM
  • Using the Microsoft Notification Service

Future post content – Windows Phone 7 development

Given that I now have the Windows Phone  Developer Tools up and running posts wil start focusing more on Windows Phone 7 development.  I have a number of posts in progress if your interested the following is a list of larger posts currently in progress

a.  Merge replication logging inside out using SQL Server, SQL Server CE and web synchronisation
b. WS-AT over WCF configuration and implementation – covers firewall, registry, certs and WS-AT command line and Windows SDK GUI.
c. Streamline WS-AT configuration using a UI without need for windows SDK UI snapin- a little something I am working on
d. Visual Studio Project Templates
e. Scheduled Windows Service with plugable architecture for scheduling tasks

At this point in time I will probably abandon the above posts for quite some time while I focus on Windows Phone dev.  If any of the above are of particular interest to you please add a comment detailing the prioritised order of the post(s) you would like to see.

What a day – dev therapy with tonights downloads + installs

When you have a bad day there is nothing better then some dev therapy = tonights downloads + installs;

  1. .NET Framework 4 full RC
  2. Visual Studio 2010 Ultimate RC
  3. Visual Studio 2010 remote debugger RC
  4. Windows Phone Developer Tools CTP includes
    • Windows Phone Emulator CTP
    • Silverlight for Windows Phone CTP
    • XNA 4.0 Game Studio CTP
  5. Microsoft Expression Blend 4 Beta
  6. Visual Studio 2010 and .NET Framework 4 Training Kit

How To Configure Storage Card for the Windows Mobile emulator

Issue: You require large files, such as a SQL Server CE database, to be used on the emulator but dont have enough space.

Solution: You can resolve this by setting up a storage card for the emulator that maps to a local folder on your PC.

Steps to configure PC:

  1. Create a folder on your local hard drive such as c:\emulator\Storage Card
    This will be configured as the storage card for your emulator in the next step
Windows Mobile Emulator Storage Card Configuration

Windows Mobile Emulator Storage Card Configuration

Steps to configure the Emulator:

  1. In Device emulator select File menu –> Configure
  2. Select the General tab
  3. Set the shared folder to c:\emulator\Storage Card in the shared textbox
  4. press ok
  5. Windows Mobile Emulator Storage Card Configuration

    Windows Mobile Emulator Storage Card Configuration

  6. On the enykatir go to File –> Reset –> Hard
  7. Once the emulator boots go to Start –> Programs –> File Explorer and select Storage card
Windows Mobile Emulator Storage Card Configuration

Windows Mobile Emulator Storage Card Configuration

Useful NativeError Range and Description links: SQL Server Compact 3.5 Service Pack 1 and SQL Server 2005 Compact Edition

Essential links for figuring out why your SQL Server Compact Edition merge replication is failing. 

SQL Server Compact Edition 3.5 Service Pack 1 NativeError List:

Category Range
Engine Errors 25000-25499
Replication Transport Errors 28000-28499
Client Agent Errors 28500-28999
Server Agent Errors 29000-29499
Message Protocol Errors 29500-29999
Query Processor errors 25500-26499
OLEDB Errors 0x80040E00L-0x00040EDDL

SQL Server Mobile 2005 Compact Edition NativeError List:

Category Range
Engine Errors 25000-27999
Replication Transport Errors 28000-28499
Client Agent Errors 28500-28999
Server Agent Errors 29000-29499
Message Protocol Errors 29500-29999
Query Processor errors 25500-26499
OLEDB Errors 0x80040E00L-0x00040EDDL

Application crash when using SQL Server Compact Edition running from storage card in the Symbol MC70

So you have got your new MC70, slapped in a storage card so that you can run your SQL Server CE database from there and found that you application keeps crashing everytime the device resumes from standby?

The issue is the default driver selection for the SD Card causes the connection to break, perform the following to resolve the issue:

  1. Press Start –> Setings –> System Tab –> SDSwitch Icon
  2. Press SDMMC Mode radio button
  3. Press No Remove On Resume checkbox
  4. Press Ok
  5. Perform a warm boot of the device as advised by dialog
 

MC70 SD Switch for SQL Server Compact=

MC70 SD Switch for SQL Server Compact Edition

How to HtmlEncode user content to avoid cross site scripting attacks

Issue:  So you have put together a website that enables users to enter content that somewhere along the line renders to the screen.  Take for example www.FishingTribute.com.   

FishingTribute.com

Fishing Tribute

 Somewhere along the way a user uploads an image and injects some javascript into a label that is rendered back to the page.  The problem is labels, image text and the like are scatterd throughout the site and you dont really want to search through and HTML encode the text of every control.   

 Solution: Well one simple answer is to come up with your own control that HTML encodes the text as it renders to the page. Create a new assembly so that you can re-use it across all your sites. The following example creates a SecureLabel control.  

using System;
using System.Web;
using System.Web.UI.WebControls;

namespace Tribute.Core.Secure
{
    public class SecureLabel: Label
    {
        private bool _XSSEncode = true;

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            if(XSSEncode && !String.IsNullOrEmpty(this.Text))
            {
                this.Text = HttpUtility.HtmlEncode(this.Text);
            }

            base.Render(writer);
        }

        public bool XSSEncode
        {
            get { return _XSSEncode; }
            set { _XSSEncode = value; }
        }
    }
} 

Lets look at the code SecureLabel inherits from Label (the one we are currently using on the page). A public XSSEncode property is available to optionally change the the default value to true (i.e always html encode unless otherwise specified).    

 Override the Render method of the Label base class is and HttpUtility.HtmlEncode the text of the control if XSSEncode is true.  

But we are still not quite there yet, just as I did not want to go through my whole websites codebase and add HttpUtility.HtmlEncode(…) everywhere I dont want to go through my whole website and replace all my Label controls with SecureLabel controls. The solution is simple use the <controlls> and <tagMapping> within your web.config to register the controls and map the .net WebControl to the newly created control as per the following  

<system.web>
   <pages >
     <controls>
           …
           <add tagPrefix=“asp“ namespace=“Tribute.Core.Secure“ assembly=“Tribute.Core“/>
      </controls>
     <tagMapping>
           <add tagType=“System.Web.UI.WebControls.Label“ mappedTagType=“Tribute.Core.Secure.SecureLabel“/>
           <add tagType=“System.Web.UI.WebControls.Image” mappedTagType=“Tribute.Core.Secure.SecureImage“/>
      <tagMapping/>
  <pages/>
<system.web/>

There you have it – a low effort no fuss solution :)

A heads up from Phil on Literals usage – use the mode=”Encode” property

An error message cannot be displayed because an optional resource assembly containing it cannot be found

Issue:  So you have a couple of Windows Mobile 5 based prod devices running a .NET Compact Framework 2.0 sp2 application ocasionally getting an error when calling a web service over SSL.  Your trusty logging logs a message along the following lines:

System.Net.WebException: An error message cannot be displayed because an optional resource assembly containing it cannot be found —> System.Net.WebException: An error message cannot be displayed because an optional resource assembly containing it cannot be found

at System.Net.SslConnectionState.PerformClientHandShake()

at System.Net.Connection.connect()

at WorkItem.doWork()

at System.Threading.Timer.ring()

Solution: So whats going on ?… well from the stackdump we can clearly see that the issue is occuring when trying to do a handshake with the remote server “System.Net.SslConnectionState.PerformClientHandShake()”  likely something to do with the cert.  So before jumping to conclusions lets see if we can get a proper error message.

The optional string resource assembly is optional to reduce the footprint of .NET Compact Framework.  To get a more useful error message out of the device the appropriate cab must be installed.  The cab to install in this instance is System_SR_ENU.cab, you can find it in C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\Diagnostics.  (Note: use System_SR_ENU_wm.cab for Windows Mobile 6.0 based devices).

After installing the cab and re-running the application a more detailed error message is displayed and indicates that the client can’t validate the SSL certificate from the remote server.  Checking the server certificate it appears to be valid and still within 2008 to 2011.  Checking the device shows that the local date time of the device has reverted back to 2005 – one of the end users must have let the backup battery go flat.   Updating the date and time back to present 2010 and hey presto issue resolved :)

hope this helps

how to unshelve, shelveset, TFS 2005, TFS 2008

Issue: you are working on a large TFS team project and you’re waiting for your co-worker to check in their changes but they are waiting on a review from the tech team lead or architect prior to doing so. You need the changes to enable you to continue developing against the library || service etc that they have created. The simple solution is to get them to check in a shelveset so that it does not break the build and you can check out the shelveset, fingers crossed the tech team lead does not make drastic changes.

Solution: To retrieve a shelvset use Unshelve pending changes: Right click solution or project Select unshelve pending changes In the owner name enter the name of your co-worker and press Find In the results select the shelveset of interest Press unshelve

How to create a SqlCeEngine CreateDatabase extension method using the .NET Compact Framework 3.5 and SQL Compact Edition 3.5

How to create a SQL Server CE 3.5 database utilisting a .NET CF 3.5 extension method:
1. Add a semi colon delimited resource file to your .NET CF mobile project.

CREATE TABLE OrderHeader(
[ID] uniqueidentifier not null,
[CustomerID] uniqueidentifier not null,
[ReqestedDlvryDate] datetime not null,
[Comments] nvarchar(1000),
[CreateDate] datetime not null,
[CreatedByID] uniqueidentifier not null,
[LastEditDate] datetime null,
[LastEditBy] uniqueidentifier not null,
CONSTRAINT [PK_OrderHeader] PRIMARY KEY  ( [ID] )
);

CREATE TABLE OrderDetail(
[ID] uniqueidentifier not null,
[OrderID] uniqueidentifier not null,
[ProductID] uniqueidentifier not null,
[Qty] int not null,
CONSTRAINT [PK_OrderDetail] PRIMARY KEY  ( [ID] ),
CONSTRAINT [FK_OrderHeader] FOREIGN KEY([OrderID]) REFERENCES [OrderHeader]([ID])
);

2. Add an extension method on System.Data.SqlServerCE.SqlCeEngine to create the
database based on the semi colon delimited string passed in from the resorce file:

using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlServerCe;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SQLCEDatabaseDemo.ExtensionMethods
{
    public static class Extensions
    {
        public static bool CreateDatabase(this SqlCeEngine sqlceDB, string commands)
        {
            bool success = false;
            SqlCeConnection sqlCon = null;
            try
            {
                sqlCon = new SqlCeConnection(sqlceDB.LocalConnectionString);
                if (!System.IO.File.Exists(sqlCon.DataSource))
                {
                    sqlceDB.CreateDatabase();
                    sqlCon.Open();
                    string[] sqlStatements = commands.Split(';');
                    SqlCeCommand cmd = sqlCon.CreateCommand(); 

                    foreach (string cmdText in sqlStatements)
                    {
                        if (!String.IsNullOrEmpty(cmdText.Trim()))
                        {
                            cmd.CommandText = cmdText; cmd.ExecuteNonQuery();
                        }
                    } success = true;
                }
            }
            finally
            {
                if (sqlCon != null)
                {
                    sqlCon.Close(); sqlCon.Dispose();
                }
            } return success;
        } 

        public static void DeleteDatabase(this SqlCeEngine sqlceDB, string path)
        {
            System.IO.File.Delete(path);
        }
    }
}

3. Execute using the following code

string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName);
string con = String.Format("data source='{0}\\testdb.sdf'; mode=Exclusive;", path);
using(System.Data.SqlServerCe.SqlCeEngine eng = new System.Data.SqlServerCe.SqlCeEngine(con))
{
    if (eng.CreateDatabase(Properties.Resources.CreateSchema))
    {
        MessageBox.Show("DB created successfully");
    }
}

Solution: SQL CE Merge Replication fails with HRESULT:-2147217887 and NativeError:28559

Issue:
SQL Mobile encountered problems when opening the database.; Another user has opened the database with different instance-level initialization properties. [ 1 ], Message:SQL Mobile encountered problems when opening the database., HRESULT: -2147217887, NativeError:28559

Solution:
You likely have another connection open to the database. Ensure that SQL CE Query analyser on the device is closed and that you have closed all connections to the mobile device from SQL Management Studio.

www.FishingTribute.com goes live

Here we go, another website rolled out for Alpha testing – Enter http://www.FishingTribute.com/ - FishingTribute.com is a site created to allow all to share pictures of their catch with other fishing enthusists around the world, its intention is to be a fun site full of user submitted images and comments. Check it out, join up and have some fun sharing what you may spend your catch. Its early days and the site is still in Alpha with a bunch more functionality on the way…

Microsoft Sync Framework 2.0 released

Microsoft Sync Framework 2.0 released 18/10/2008. The Microsoft Sync Framework 2.0 SDK is also worth grabbing. Venture forth and build your sync apps :) – but remember to filter your data, its the number one issue I find every time that I am asked to troubleshoot a poorly performing Sync App. Keep this in mind during development and you’ll have a much easier time as the system grows to in terms of number of subscribing clients and amount of data on the serverside.