Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Windows Phone 7 series, Silverlight, XNA, Compact Framework, Background Processing and… Symbian S60

So here are a few things I found interesting from the first day of MIX:

- Windows Phone 7 series…. duh, well yes that one was obvious. It seems that nearly everyone is talking about it. In case you’ve been living in a hole somewhere you’ll have noticed that the development story is Silverlight and XNA for this platform

- Compact Framework v3.7. If you inspect System.Environment.OSVersion in the emulator you’ll see that it reports version Microsoft Windows CE 7.0.6077. This is confirmed by this post that talks about the WP7 Programming Model.

- Background Processing – That’s right, if you’re application is a good phone citizen (as defined by Microsoft of course) and you don’t consume too many resources your application will continue to operate in the background. This is demonstrable in the emulator if you create a background thread that increments a counter or prints a debug statement – when your application looses focus it will continue to increment/print.

- Symbian S60 support for Silverlight (in-browser model). The Silverlight model for WP7 is entirely out of browser. In fact your Silverlight application will be deployed via Marketplace and will not have any contact as such with the browser. S60 support, as discussed in the post Silverlight on Nokia S60 platform, is in-browser and is only a very limited subset of Silverlight 2. The obvious questions here are whether WP7 will get SL in-browser support (they’ve already been talking about Flash inclusion but why not SL) and which other platforms will be next to get in-browser support.

I’m sure there will be plenty more bits emerging from MIX over the coming days.

WCF on Windows Mobile and .NET Compact Framework

I was just listening to Don, Dave and James on the second of the Jumpstart series for the Codemasons’ Guild and the topic of communicating via WCF came up.  Now typically when I build mobile apps I don’t go through all the pain of using WCF, I simply use a regular asmx web service and then use Add Web Reference to add it to my mobile project.  To secure it, I just communicate over SSL. If you do want/need to use WCF on the server side, there are a couple of options to do this.

Before we jump into how you use WCF, let me point out a couple of useful powertoys:

The Power Toys for .NET CF include NetCFSvcUtil.exe which is a device equivalent of SvcUtil.exe and is needed in order generate the WCF proxy.

Firstly, you need to be aware that the .NET CF has some severe limitations when it comes to WCF.  Unfortunately the only binding that is supported (excluding the much over-hyped WCF via Exchange) is basicHttpBinding. For the WCF service you want to consume you need to change it from using the default wsHttpBinding.  This can be done by launching the Tools > WCF Service Configuration Editor from Visual Studio. Open the web.config file for the WCF Service project.  Under Endpoints, adjust the Binding to basicHttpBinding.

image

Save this change and run the WCF Service.

Now to the options…..

1) The first option is to use Add Web Reference.  This is by far the simplest approach as you can click Browse to: Web services in this solution.  Select your service and click Add Reference. 

image

Once you have added the reference you can call your service method the same way you would from a regular desktop application:

localhost.Service1 service = new localhost.Service1();
service.Url = service.Url.Replace("localhost", "192.168.1.2");
return service.GetData(5, true);

Note: You have to change the “localhost” host name to something that can be resolved by the device.  I typically just use the ip address of the development machine.  Clearly for production you will want to specify this in a configuration file or make it a configurable setting within your application.

2) The second option is to use NetCFSvcUtil.exe to generate the appropriate WCF proxy information. Start by opening up the Visual Studio command prompt (Start > Microsoft Visual Studio 2008 > Visual Studio Tools > Visual Studio 2008 Command Prompt) and adding the path to the Compact Framework power toys:

>> set path=%path%;C:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\bin

Navigate to the folder where you want the proxy files to be created and then use NetCFSvcUtil.  I figured this would be quite simple but it appears that somewhere between Vista SP1 and SP2 (and there are reports of this problem on Windows 7 too) a bug in NETCFSvcUtil surfaced preventing it from working.

image

As you can see the error message is really helpful:

Error: An error occurred in the tool.
Error: Error in the application.

Currently, there doesn’t seem to be a workaround for this.  Some people have had varied success by changing the parameters and return types of the service methods.  The one strategy I used that appears to work is to use a combination of SvcUtil and NetCFSvcUtil.

>> svcutil.exe c:\temp\WindowsMobileServices\MyDataServices\bin\MyDataServices.dll

Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation.  All rights reserved.

Generating metadata files...
C:\temp\WindowsMobileServices\WindowsMobileServices\tempuri.org.wsdl
C:\temp\WindowsMobileServices\WindowsMobileServices\tempuri.org.xsd
C:\temp\WindowsMobileServices\WindowsMobileServices\schemas.microsoft.com.2003.1
0.Serialization.xsd

>> netcfsvcutil.exe tempuri.org.wsd tempuri.org.xsd
Microsoft (R) .NET Compact Framework Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.5.0.0]
Copyright (c) Microsoft Corporation.  All rights reserved.

Generating files...
C:\temp\WindowsMobileServices\WindowsMobileServices\tempuri.org.cs
C:\temp\WindowsMobileServices\WindowsMobileServices\CFClientBase.cs

Now, include all the generated file into your mobile project.  You will also need to add references to System.ServiceModel and System.Runtime.Serialization.

In order to call your service method you can now write the following:

var binding = System.ServiceModel.BasicHttpBinding();
var endpoint = System.ServiceModel.EndpointAddress("http://192.168.1.2:6323/Service1.svc");
Service1Client client = new Service1Client(new binding, new endpoint
);
return client.GetData(5);

So, the question is why would you go the second option?  Well if you actually look at the generated code, adding the WCF service using Add Web Reference adds a bunch of unnecessary fields.  When calling the method GetData there is a second parameter called “valueSpecified” which is little more than a flag to indicate if the first parameter was specified or not.  This is not required if you use the second option to generate the proxy information.

More Windows Mobile Controls for .NET Compact Framework with Mirabyte

I noticed Frank’s post on the new Touch Controls Suite 1.0 from Mirabyte.  It’s hard to do the UI justice, particularly because the YouTube video they have on the page uses such horrible colours.  I do like how it appears in Visual Studio and I think the nice touch responsiveness (in WM5 and WM6 apparently) looks great.

image image

It’s great to see more and more controls being built to help Windows Mobile developers build rich user interfaces.

Advanced Graphics with .NET Compact Framework

Building managed applications for Windows Mobile devices that have a rich user interface is almost impossible if you restrict yourself to the primitive controls that ship with the .NET Compact Framework.  Luckily building your own custom controls isn't that difficult.  You typically have to override the painting of the control to render the content the way you want it.  Unfortunately if you want to do some more complex rendering you will still run into problems because the Graphics object that is exposed by the OnPaint event is a significantly reduced subset of the desktop Graphics object.  The main things it misses are the ability to transform (scale, rotate and translate) the graphics.

Lets take an example, say you have a method that draws a cross:

Private Sub DrawCross(ByVal g As Graphics, 
                               ByVal size As Integer)
    g.DrawLine(mForegroundPen, -size, -size, size, size)
    g.DrawLine(mForegroundPen, size, -size, -size, size)
End Sub

As you can see from this method it draws the cross based around the origin.  This is great but the likelihood of you wanting to draw a cross at the origin is virtually 0 since only a quarter of it would be visible.  There are a couple of options in terms of positioning the cross.  Firstly, you can modify the DrawCross method to accept a third parameter that identifies the centre of the cross:

Private Sub DrawCross(ByVal g As Graphics, _
                               ByVal centre As Point, _
                               ByVal size As Integer)
    g.DrawLine(mForegroundPen, centre.X - size, centre.Y - size, _
                                           
centre.X + size, centre.Y + size)
    g.DrawLine(mForegroundPen, centre.X + size, centre.Y - size, _
                                            centre.X - size, centre.Y + size)
End Sub

Now all of a sudden the method has become significantly less readable and you can imagine how it would get if the rendering was more complex than just a cross. The second way to do this, and my preference, is to translate the centre of the graphics canvas.  This way the DrawCross method doesn't change - it still things it's drawing at the origin - just the canvas that you are drawing on does.  A way to visualise this is to imagine a pen suspended in mid air ready to draw a cross on the canvas below it.  What we want to do is reposition the canvas underneath so that when the pen draws the cross, the cross is actually at the required position in the canvas.  When we are done, we have to remember to reset the canvas so that other drawing is done at the right place.  We can do this as follows:

Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs)
    MyBase.OnPaint(pe)

    Dim g As Graphics = pe.Graphics
   
g.Clear(Me.BackColor)
   
    g.TranslateTransform(Me.Width / 2, Me.Height / 2)
    DrawCross(g, 10)
    g.ResetTransform()
End Sub

As you can see it is clear from here what is going on - we are moving to the centre of the control, drawing the cross with size 10 and then resetting the canvas (just in case other methods are added).

Going back to the original discussion around the .NET Compact Framework you will notice that the TranslateTransform method doesn't exist on the Graphics object.  I'm guessing that part of the reason for this is the lack of support from the underlying rendering engine but here's quite a simple way to get around this issue (be warned though, calculations involved in doing these operations can quickly become CPU intensive which can make your application slow and consume battery power!).  You need to create a wrapper graphics class that is capable of doing the layout changes you want:

Public Class TranformGraphics
    Private mGraphics As Graphics
    Private mMatrix As TMatrix

    Public Sub New(ByVal g As Graphics)
        Me.mGraphics = g
    End Sub

    Public Sub DrawLine(ByVal pen As Pen, ByVal x1 As Integer, _
                                                        ByVal y1 As Integer, _
                                                        ByVal x2 As Integer, _
                                                        ByVal y2 As Integer) 
        Me.mGraphics.DrawLine(pen, ConvertedX(x1, y1), _
                                                ConvertedY(x1, y1), _
                                                ConvertedX(x2, y2), _
                                                ConvertedY(x2, y2))
    End Sub

    Private Function ConvertedX(ByVal x As Integer, _
                                           ByVal y As Integer) As Integer
        If Me.mMatrix Is Nothing Then Return x
        Return CInt(mMatrix.R1C1 * x + mMatrix.R1C2 * y + mMatrix.DX)
    End Function

    Private Function ConvertedY(ByVal x As Integer, _
                                           ByVal y As Integer) As Integer
        If Me.mMatrix Is Nothing Then Return y
        Return CInt(mMatrix.R2C1 * x + mMatrix.R2C2 * y + mMatrix.DY)
    End Function

    Public Sub ResetTransform()
        mMatrix = Nothing
    End Sub

    Public Sub TranslateTransform(ByVal dx As Single, ByVal dy As Single)
        Dim trans As New TMatrix(1, 0, 0, 1, dx, dy)
        If mMatrix Is Nothing Then
            mMatrix = trans
        Else
            mMatrix = mMatrix.Multiply(trans)
        End If
    End Sub
End Class

I've left the implementation of TMatrix to your imagination but the important method that you need to get right is the matrix multiplication:

Public Function Multiply(ByVal M1 As TMatrix) As TMatrix
    Dim M2 As TMatrix = Me

    Return New TMatrix(M2.R1C1 * M1.R1C1 + M2.R1C2 * M1.R2C1, _
                        M2.R1C1 * M1.R1C2 + M2.R1C2 * M1.R2C2, _
                        M2.R2C1 * M1.R1C1 + M2.R2C2 * M1.R2C1, _
                        M2.R2C1 * M1.R1C2 + M2.R2C2 * M1.R2C2, _
                        M2.R1C1 * M1.DX + M2.R1C2 * M1.DY + M2.DX, _
                        M2.R2C1 * M1.DX + M2.R2C2 * M1.DY + M2.DY)
End Function

There might be an easier way to do this with existing classes, so if you come across something please let me know.  Now back to our code - instead of using the Graphics.TranslateTransform (which doesn't exist for the .NET CF), we can now use our newly created TransformGraphics.TranslateTransform:

Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs)
    MyBase.OnPaint(pe)

    Dim g As new TransformGraphics(pe.Graphics)
   
g.Clear(Me.BackColor)
   
    g.TranslateTransform(Me.Width / 2, Me.Height / 2)
    DrawCross(g, 10)
    g.ResetTransform()
End Sub

Private Sub DrawCross(ByVal g As TransformGraphics, 
                               ByVal size As Integer)
    g.DrawLine(mForegroundPen, -size, -size, size, size)
    g.DrawLine(mForegroundPen, size, -size, -size, size)
End Sub

Note we have still had to modify the DrawCross method so that it accepts a TransformGraphics but overall we haven't really affected the readability of the code.  Please feel free to comment on how you get around the challenges of complex rendering using the .NET Compact Framework!

Power Tools for .NET Compact Framework v3.5

Microsoft have just released the Power Tools for the .NET CF v3.5 B2 that can be download here, which includes:

  • Remote Performance Monitor and GC Heap Viewer
  • NETCF CLR Profiler
  • App Configuration Tool
  • NETCF ServiceModel Metadata Tool
  • Remote Logging Configuration Tool
  • NETCF Network Log Viewer

There are a few known issues (like 25+) but most of them are with the CLR Profiler.

.NET Compact Framework Answers Here

Well actually not quite here - you will have to wait for the .NET Compact Framework Chat to be hosted by Neil Cowburn, of OpenNETCF fame, on the 29th August.

If you have some burning .NET CF, or other mobile development, questions then you should book mark this chat as there will be a swag of MVPs, Microsofties and of course the OpenNETCF team there to answer them.

You can enter the chat here: http://chat.opennetcf.com/
August 29, 6pm - 7pm (London), 10am - 11am (Redmond)

Neil has also committed to making a transcript of the chat available via his blog for those people, such as myself, who might prefer to get some sleep at that time of day.

.NET Compact Framework 3.5 Redistributables

Anyone working with Visual Studio "Orcas" to build mobile applications should be aware that the v3.5 Beta 1 Redistributable are now available from MS Downloads.  There is also a good list of the new features that have been added to v3.5 of the .NET CF.

If you have been following Mark's blog and have been wondering why the WCF over Email sample doesn't work you will be relieved to know it's not just you!  The redistributables are NOT the same binaries as what comes with the Orcas B1 installation/VPC. The redistributables actually contain a fix as documented on the download site.

Bug Fix
The beta1 build of the .NET Compact Framework which shipped in Visual Studio ‘Orcas’ Beta1 does not allow for any project referencing Microsoft.ServiceModel.Channels.Mail* dlls to be compiled. If you’re using Orcas Beta1 and you need to build using these dll’s, first uninstall .NET Compact Framework v3.5 beta1 then download and install this version of NETCFSetupv35.msi.

Logging options for .NET Compact Framework

Since the first coffee meeting I have been hassling Alan to start blogging.  After migrating the user group's website across to Community Server I was able to set a blog up for him and he just submitted his first post.  One of the pain points for a number of mobile developers is what to use for logging.  Most developers end up doing their own custom solution.  At Intilecta we ripped out most of the useful bits from the Patterns and Practices Enterprise Library.  Based on what Alan has to say in his post I think I would definitely look at log4net as it seems to be quite comprehensive and it runs on the .NET Compact Framework.

.NET Compact Framework v1 revisited

It's always amazing what you find when you trawl through your unread emails.  Normally I'm pretty good at reading and processing those emails that need immediate attention, which is why this email got passed over until now (only a week or so old).  The innovative team over at Red FIVE Labs have ported a version of the .NET Compact Framework v1 to the Symbian OS.  How cool is that! You can now run your applications, apparently "without change".  Although there are a number of conditions that are layed out in the FAQ - such as in v1 they are really only targeting smartphone style devices and there is no support for SQL Server CE (since this is clearly a native win mobile application)

SP1 Beta for the .NET Compact Framework V2.0

I guess this is pretty old news already, but since this is an area of interest to me I thought that I should at least add to the clutter on the Internet by blogging the fact that a Beta for SP1 for the .NET Compact Framework has been announced and that more information on the added functionality and bug fixes is available on the team's blog