Tuesday 22 September 2009

SharpMap.Wpf

I've been wanting to write a WPF renderer for SharpMap ever since I started using version 0.9 about a year ago. Sure, SharpMap v2 has a few early WPF implementations, but its been in beta for quite some time now.

Our existing WPF/SharpMap solution involves using the plain old GDI+ stuff and blatting the entire map into a WPF image using Interop Bitmap. It does the job quite well, so why bother doing anything more?

Well, mainly cos I wanted to! but also because I like the idea of having true WPF styles and themes. The improved brushes in WPF mean that there is scope for some really pretty maps. Also, the idea of using several WPF images to host transparent layers and animated overlays is quite appealing.


So far, I've got a WPF map renderer up and running for vector layers only. I'm currently working on WPFing the LabelLayer and the GdalRasterLayer. Maybe, when its getting to a semi-finished state i'll try and host it on CodePlex. I guess it all depends if anyone is still interested in 0.9 by then!?
A few interesting points on the current state of play:
  • At first I started to write a dedicated WpfVectorLayer and a corresponding WpfVectorRenderer, but I just couldn't live with the code smell. There was too much redundant duplication. In the end, I refactored the VectorLayer into a new generic class with a templatable style and introduced a new Render method that used an IRenderContext instead of a Graphics object. I now have two concrete implementations of IRenderContext, one for GDI+ and one for WPF. To this end, you can declare concrete instances of the generic VectorLayer that either use the standard VectorStyle or the new WpfVectorStyle, depending upon the type of renderer you wish to use.

  • Due to the departure from the original design, all the new stuff is in a separate namespace. The 'legacy' VectorLayer has been left unchanged (yeah, so I've still ended up duplicating code, but at least moving forward you need only implement an IRenderContext)

  • The WPF renderer uses the stream geometry classes to draw straight to a WPF DrawingContext. In addition to this, it provides methods to render the entire map, or just a single layer, to a Visual or a BitmapSource.
Here is my SharpMap.Wpf 'hello world':

4 comments:

  1. Great stuff Kev!

    I have also been working on adding advancements to the sharpmap 0.9 instance since 2.0 seems to be taking a rather long time to implement - any plans to opensource your work and contribute this back to the codeplex project?

    regards,

    Kevin S.

    ReplyDelete
  2. The images i get are not clear when I zoomed in with image control in wpf. When .net 2.o picturebox control is used the maps rendered are clear even when zoomed.

    I am using this code;

    myMap = new MapBase.MapManager();
    Path = new PathIndicator.PathManager();
    Path.loadBuffer(myMap);

    myMap.Map.ZoomToExtents();
    //convert System.Drawing.Image to WPF image
    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(myMap.Map.GetMap());

    IntPtr hBitmap = bmp.GetHbitmap();
    System.Windows.Media.ImageSource WpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

    imgCurrent.Source = WpfBitmap;

    How can I use it without creating an image?
    Any help would be greatly appreciated.

    ReplyDelete
  3. Hmm, i was going to suggest posting this question to the SharpMap discussions but i can see you have already done that!

    Basically, you just have to recreate the image (using CreateBitmapSourceFromHBitmap) every time you zoom in or the map extents change.

    Simply zooming the image wont achieve anything.

    Cheers,
    Kev.

    ReplyDelete
  4. Thanks for the idea.. then I'll go through image recreation or shift back to .net 2.o. :(

    ReplyDelete